diff --git a/src/timeline/CMakeLists.txt b/src/timeline/CMakeLists.txt deleted file mode 100644 index 32141d5a5..000000000 --- a/src/timeline/CMakeLists.txt +++ /dev/null @@ -1,4 +0,0 @@ -set(kdenlive_SRCS - ${kdenlive_SRCS} - PARENT_SCOPE) - diff --git a/src/timeline/abstractclipitem.cpp b/src/timeline/abstractclipitem.cpp deleted file mode 100644 index fad990738..000000000 --- a/src/timeline/abstractclipitem.cpp +++ /dev/null @@ -1,686 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Marco Gittler (g.marco@freenet.de) * - * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "abstractclipitem.h" -#include "customtrackscene.h" -#include "customtrackview.h" -#include "kdenlivesettings.h" - -#include "mlt++/Mlt.h" - -#include - -#include -#include -#include -#include - -AbstractClipItem::AbstractClipItem(const ItemInfo &info, const QRectF &rect, double fps) - : QObject() - , QGraphicsRectItem(rect) - , m_info(info) - , m_visibleParam(0) - , m_selectedEffect(-1) - , m_fps(fps) - , m_isMainSelectedClip(false) - , m_keyframeView(QFontInfo(QApplication::font()).pixelSize() * 0.7, this) -{ - setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); - setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); - setFlag(QGraphicsItem::ItemUsesExtendedStyleOption, true); - setPen(Qt::NoPen); - connect(&m_keyframeView, &KeyframeView::updateKeyframes, this, &AbstractClipItem::doUpdate); - m_selectionTimer.setSingleShot(true); - m_selectionTimer.setInterval(1000); - QObject::connect(&m_selectionTimer, &QTimer::timeout, this, &AbstractClipItem::slotSelectItem); -} - -AbstractClipItem::~AbstractClipItem() -{ -} - -void AbstractClipItem::doUpdate(const QRectF &r) -{ - update(r); -} - -void AbstractClipItem::updateKeyFramePos(int frame, const double y) -{ - m_keyframeView.updateKeyFramePos(rect(), frame, qBound(0.0, y, rect().height())); -} - -void AbstractClipItem::prepareKeyframeMove() -{ - m_keyframeView.originalKeyframe = m_keyframeView.activeKeyframe; -} - -int AbstractClipItem::selectedKeyFramePos() const -{ - return m_keyframeView.activeKeyframe; -} - -int AbstractClipItem::originalKeyFramePos() const -{ - return m_keyframeView.originalKeyframe; -} - -int AbstractClipItem::keyframesCount() -{ - return m_keyframeView.keyframesCount(); -} - -double AbstractClipItem::editedKeyFrameValue() -{ - return m_keyframeView.editedKeyFrameValue(); -} - -double AbstractClipItem::getKeyFrameClipHeight(const double y) -{ - return m_keyframeView.getKeyFrameClipHeight(rect(), y); -} - -bool AbstractClipItem::isAttachedToEnd() const -{ - return m_keyframeView.activeKeyframe == m_keyframeView.attachToEnd; -} - -QAction *AbstractClipItem::parseKeyframeActions(const QList &list) -{ - return m_keyframeView.parseKeyframeActions(list); -} - -void AbstractClipItem::closeAnimation() -{ - if (!isEnabled()) { - return; - } - setEnabled(false); - setFlag(QGraphicsItem::ItemIsSelectable, false); - if (QApplication::style()->styleHint(QStyle::SH_Widget_Animate, nullptr, QApplication::activeWindow()) != 0) { - // animation disabled - deleteLater(); - return; - } - QPropertyAnimation *closeAnimation = new QPropertyAnimation(this, "rect"); - QPropertyAnimation *closeAnimation2 = new QPropertyAnimation(this, "opacity"); - closeAnimation->setDuration(200); - closeAnimation2->setDuration(200); - QRectF r = rect(); - QRectF r2 = r; - r2.setLeft(r.left() + r.width() / 2); - r2.setTop(r.top() + r.height() / 2); - r2.setWidth(1); - r2.setHeight(1); - closeAnimation->setStartValue(r); - closeAnimation->setEndValue(r2); - closeAnimation->setEasingCurve(QEasingCurve::InQuad); - closeAnimation2->setStartValue(1.0); - closeAnimation2->setEndValue(0.0); - auto *group = new QParallelAnimationGroup; - connect(group, &QAbstractAnimation::finished, this, &QObject::deleteLater); - group->addAnimation(closeAnimation); - group->addAnimation(closeAnimation2); - group->start(QAbstractAnimation::DeleteWhenStopped); -} - -ItemInfo AbstractClipItem::info() const -{ - ItemInfo info = m_info; - info.cropStart = cropStart(); - info.endPos = endPos(); - return info; -} - -GenTime AbstractClipItem::endPos() const -{ - return m_info.startPos + m_info.cropDuration; -} - -int AbstractClipItem::track() const -{ - return m_info.track; -} - -GenTime AbstractClipItem::cropStart() const -{ - return m_info.cropStart; -} - -GenTime AbstractClipItem::cropDuration() const -{ - return m_info.cropDuration; -} - -void AbstractClipItem::setCropStart(const GenTime &pos) -{ - m_info.cropStart = pos; -} - -void AbstractClipItem::updateItem(int track) -{ - m_info.track = track; - m_info.startPos = GenTime((int)scenePos().x(), m_fps); - if (m_info.cropDuration > GenTime()) { - m_info.endPos = m_info.startPos + m_info.cropDuration; - } -} - -void AbstractClipItem::updateRectGeometry() -{ - setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height()); -} - -void AbstractClipItem::resizeStart(int posx, bool hasSizeLimit, bool /*emitChange*/) -{ - GenTime durationDiff = GenTime(posx, m_fps) - m_info.startPos; - if (durationDiff == GenTime()) { - return; - } - - if (type() == AVWidget && hasSizeLimit && (cropStart() + durationDiff < GenTime())) { - durationDiff = GenTime() - cropStart(); - } else if (durationDiff >= cropDuration()) { - return; - } - m_info.startPos += durationDiff; - m_keyframeView.setOffset(durationDiff.frames(m_fps)); - // set to true if crop from start is negative (possible for color clips, images as they have no size limit) - bool negCropStart = false; - if (type() == AVWidget) { - m_info.cropStart += durationDiff; - if (m_info.cropStart < GenTime()) { - negCropStart = true; - } - } - m_info.cropDuration -= durationDiff; - setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height()); - moveBy(durationDiff.frames(m_fps), 0); - - if (m_info.startPos != GenTime(posx, m_fps)) { - GenTime diff = m_info.startPos - GenTime(posx, m_fps); - - if (type() == AVWidget) { - m_info.cropStart += diff; - } - - m_info.cropDuration -= diff; - setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height()); - } - // set crop from start to 0 (isn't relevant as this only happens for color clips, images) - if (negCropStart) { - m_info.cropStart = GenTime(); - } -} - -void AbstractClipItem::resizeEnd(int posx, bool /*emitChange*/) -{ - GenTime durationDiff = GenTime(posx, m_fps) - endPos(); - if (durationDiff == GenTime()) { - return; - } - if (cropDuration() + durationDiff <= GenTime()) { - durationDiff = GenTime() - (cropDuration() - GenTime(3, m_fps)); - } - - m_info.cropDuration += durationDiff; - m_info.endPos += durationDiff; - - setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height()); - if (durationDiff > GenTime()) { - QList collisionList = collidingItems(Qt::IntersectsItemBoundingRect); - bool fixItem = false; - for (int i = 0; i < collisionList.size(); ++i) { - if (!collisionList.at(i)->isEnabled()) { - continue; - } - QGraphicsItem *item = collisionList.at(i); - if (item->type() == type() && item->pos().x() > pos().x()) { - GenTime diff = static_cast(item)->startPos() - startPos(); - if (!fixItem || diff < m_info.cropDuration) { - fixItem = true; - m_info.cropDuration = diff; - } - } - } - if (fixItem) { - setRect(0, 0, cropDuration().frames(m_fps) - 0.02, rect().height()); - } - } -} - -GenTime AbstractClipItem::startPos() const -{ - return m_info.startPos; -} - -double AbstractClipItem::fps() const -{ - return m_fps; -} - -void AbstractClipItem::updateFps(double fps) -{ - m_fps = fps; - setPos((qreal)startPos().frames(m_fps), pos().y()); - updateRectGeometry(); -} - -GenTime AbstractClipItem::maxDuration() const -{ - return m_maxDuration; -} - -CustomTrackScene *AbstractClipItem::projectScene() -{ - if (scene()) { - return static_cast(scene()); - } - return nullptr; -} - -void AbstractClipItem::setItemLocked(bool locked) -{ - if (locked) { - setSelected(false); - } - - // Allow move only if not in a group - if (locked || parentItem() == nullptr) { - setFlag(QGraphicsItem::ItemIsMovable, !locked); - } - setFlag(QGraphicsItem::ItemIsSelectable, !locked); -} - -bool AbstractClipItem::isItemLocked() const -{ - return !(flags() & (QGraphicsItem::ItemIsSelectable)); -} - -// virtual -void AbstractClipItem::mousePressEvent(QGraphicsSceneMouseEvent *event) -{ - if ((event->modifiers() & Qt::ShiftModifier) != 0u) { - // User want to do a rectangle selection, so ignore the event to pass it to the view - event->ignore(); - } else { - QGraphicsItem::mousePressEvent(event); - } -} - -// virtual -void AbstractClipItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) -{ - if ((event->modifiers() & Qt::ControlModifier) != 0u) { - // User want to do a rectangle selection, so ignore the event to pass it to the view - event->ignore(); - } else { - QGraphicsItem::mouseReleaseEvent(event); - } -} - -void AbstractClipItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) -{ - if (event->buttons() != Qt::LeftButton || ((event->modifiers() & Qt::ControlModifier) != 0u)) { - // User want to do a rectangle selection, so ignore the event to pass it to the view - event->ignore(); - } else { - QGraphicsItem::mouseMoveEvent(event); - } -} - -void AbstractClipItem::slotSelectItem() -{ - emit selectItem(this); -} - -int AbstractClipItem::itemHeight() -{ - return 0; -} - -int AbstractClipItem::itemOffset() -{ - return 0; -} - -void AbstractClipItem::setMainSelectedClip(bool selected) -{ - if (selected == m_isMainSelectedClip) { - return; - } - m_isMainSelectedClip = selected; - update(); -} - -bool AbstractClipItem::isMainSelectedClip() -{ - return m_isMainSelectedClip; -} - -int AbstractClipItem::trackForPos(int position) -{ - int track = 1; - if ((scene() == nullptr) || scene()->views().isEmpty()) { - return track; - } - CustomTrackView *view = static_cast(scene()->views()[0]); - if (view) { - track = view->getTrackFromPos(position); - } - return track; -} - -int AbstractClipItem::posForTrack(int track) -{ - int pos = 0; - if ((scene() == nullptr) || scene()->views().isEmpty()) { - return pos; - } - CustomTrackView *view = static_cast(scene()->views()[0]); - if (view) { - pos = view->getPositionFromTrack(track) + 1; - } - return pos; -} - -void AbstractClipItem::attachKeyframeToEnd(const QDomElement &effect, bool attach) -{ - QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - if (e.isNull()) { - continue; - } - QString paramName = e.attribute(QStringLiteral("name")); - if (m_keyframeView.activeParam(paramName) && e.attribute(QStringLiteral("type")) == QLatin1String("animated")) { - m_keyframeView.attachKeyframeToEnd(attach); - e.setAttribute(QStringLiteral("value"), m_keyframeView.serialize()); - } - } -} - -void AbstractClipItem::editKeyframeType(const QDomElement &effect, int type) -{ - QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - if (e.isNull()) { - continue; - } - QString paramName = e.attribute(QStringLiteral("name")); - if (m_keyframeView.activeParam(paramName) && e.attribute(QStringLiteral("type")) == QLatin1String("animated")) { - m_keyframeView.editKeyframeType(type); - e.setAttribute(QStringLiteral("value"), m_keyframeView.serialize()); - } - } -} - -void AbstractClipItem::insertKeyframe(QDomElement effect, int pos, double val, bool defaultValue) -{ - if (effect.attribute(QStringLiteral("disable")) == QLatin1String("1")) { - return; - } - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - effect.setAttribute(QStringLiteral("active_keyframe"), pos); - QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - if (e.isNull()) { - continue; - } - QString paramName = e.attribute(QStringLiteral("name")); - if (e.attribute(QStringLiteral("type")) == QLatin1String("animated")) { - if (!m_keyframeView.activeParam(paramName)) { - continue; - } - if (defaultValue) { - m_keyframeView.addDefaultKeyframe(pos, m_keyframeView.type(pos)); - } else { - m_keyframeView.addKeyframe(pos, val, m_keyframeView.type(pos)); - } - // inserting a keyframe touches all animated params - for (int j = 0; j < params.count(); ++j) { - QDomElement f = params.item(j).toElement(); - if (f.attribute(QStringLiteral("type")) != QLatin1String("animated") && f.attribute(QStringLiteral("type")) != QLatin1String("animatedrect")) { - continue; - } - f.setAttribute( - QStringLiteral("value"), - m_keyframeView.serialize(f.attribute(QStringLiteral("name")), f.attribute(QStringLiteral("type")) == QLatin1String("animatedrect"))); - } - } else if (e.attribute(QStringLiteral("type")) == QLatin1String("keyframe") || e.attribute(QStringLiteral("type")) == QLatin1String("simplekeyframe")) { - QString kfr = e.attribute(QStringLiteral("keyframes")); - const QStringList keyframes = kfr.split(QLatin1Char(';'), QString::SkipEmptyParts); - QStringList newkfr; - bool added = false; - for (const QString &str : keyframes) { - int kpos = str.section(QLatin1Char('='), 0, 0).toInt(); - double newval = locale.toDouble(str.section(QLatin1Char('='), 1, 1)); - if (kpos < pos) { - newkfr.append(str); - } else if (!added) { - if (i == m_visibleParam) { - newkfr.append(QString::number(pos) + QLatin1Char('=') + QString::number((int)val)); - } else { - newkfr.append(QString::number(pos) + QLatin1Char('=') + locale.toString(newval)); - } - if (kpos > pos) { - newkfr.append(str); - } - added = true; - } else { - newkfr.append(str); - } - } - if (!added) { - if (i == m_visibleParam) { - newkfr.append(QString::number(pos) + QLatin1Char('=') + QString::number((int)val)); - } else { - newkfr.append(QString::number(pos) + QLatin1Char('=') + e.attribute(QStringLiteral("default"))); - } - } - e.setAttribute(QStringLiteral("keyframes"), newkfr.join(QLatin1Char(';'))); - } - } -} - -void AbstractClipItem::movedKeyframe(QDomElement effect, int newpos, int oldpos, double value) -{ - if (effect.attribute(QStringLiteral("disable")) == QLatin1String("1")) { - return; - } - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - effect.setAttribute(QStringLiteral("active_keyframe"), newpos); - QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter")); - int start = cropStart().frames(m_fps); - int end = (cropStart() + cropDuration()).frames(m_fps) - 1; - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - if (e.isNull()) { - continue; - } - QString paramName = e.attribute(QStringLiteral("name")); - if (e.attribute(QStringLiteral("type")).startsWith(QLatin1String("animated"))) { - if (m_keyframeView.activeParam(paramName)) { - // inserting a keyframe touches all animated params - for (int j = 0; j < params.count(); ++j) { - QDomElement f = params.item(j).toElement(); - if (f.attribute(QStringLiteral("type")) != QLatin1String("animated") && - f.attribute(QStringLiteral("type")) != QLatin1String("animatedrect")) { - continue; - } - f.setAttribute( - QStringLiteral("value"), - m_keyframeView.serialize(f.attribute(QStringLiteral("name")), f.attribute(QStringLiteral("type")) == QLatin1String("animatedrect"))); - } - } - } else if ((e.attribute(QStringLiteral("type")) == QLatin1String("keyframe") || - e.attribute(QStringLiteral("type")) == QLatin1String("simplekeyframe"))) { - QString kfr = e.attribute(QStringLiteral("keyframes")); - const QStringList keyframes = kfr.split(QLatin1Char(';'), QString::SkipEmptyParts); - QStringList newkfr; - for (const QString &str : keyframes) { - if (str.section(QLatin1Char('='), 0, 0).toInt() != oldpos) { - newkfr.append(str); - } else if (newpos != -1) { - newpos = qBound(start, newpos, end); - if (i == m_visibleParam) { - newkfr.append(QString::number(newpos) + QLatin1Char('=') + locale.toString(value)); - } else { - newkfr.append(QString::number(newpos) + QLatin1Char('=') + str.section(QLatin1Char('='), 1, 1)); - } - } - } - e.setAttribute(QStringLiteral("keyframes"), newkfr.join(QLatin1Char(';'))); - } else if (e.attribute(QStringLiteral("type")) == QLatin1String("geometry")) { - QString kfr = e.attribute(QStringLiteral("value")); - const QStringList keyframes = kfr.split(QLatin1Char(';'), QString::SkipEmptyParts); - QStringList newkfr; - for (const QString &str : keyframes) { - if (str.section(QLatin1Char('='), 0, 0).toInt() != oldpos) { - newkfr.append(str); - } else if (newpos != -1) { - newpos = qBound(0, newpos, end); - newkfr.append(QString::number(newpos) + QLatin1Char('=') + str.section(QLatin1Char('='), 1, 1)); - } - } - e.setAttribute(QStringLiteral("value"), newkfr.join(QLatin1Char(';'))); - } - } - - updateKeyframes(effect); - update(); -} - -void AbstractClipItem::removeKeyframe(QDomElement effect, int frame) -{ - if (effect.attribute(QStringLiteral("disable")) == QLatin1String("1")) { - return; - } - effect.setAttribute(QStringLiteral("active_keyframe"), 0); - QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - if (e.isNull()) { - continue; - } - if ((e.attribute(QStringLiteral("type")) == QLatin1String("keyframe") || e.attribute(QStringLiteral("type")) == QLatin1String("simplekeyframe"))) { - QString kfr = e.attribute(QStringLiteral("keyframes")); - const QStringList keyframes = kfr.split(QLatin1Char(';'), QString::SkipEmptyParts); - QStringList newkfr; - for (const QString &str : keyframes) { - if (str.section(QLatin1Char('='), 0, 0).toInt() != frame) { - newkfr.append(str); - } - } - e.setAttribute(QStringLiteral("keyframes"), newkfr.join(QLatin1Char(';'))); - } else if (e.attribute(QStringLiteral("type")) == QLatin1String("geometry")) { - QString kfr = e.attribute(QStringLiteral("value")); - const QStringList keyframes = kfr.split(QLatin1Char(';'), QString::SkipEmptyParts); - QStringList newkfr; - for (const QString &str : keyframes) { - if (str.section(QLatin1Char('='), 0, 0).toInt() != frame) { - newkfr.append(str); - } - } - e.setAttribute(QStringLiteral("value"), newkfr.join(QLatin1Char(';'))); - } else if (e.attribute(QStringLiteral("type")) == QLatin1String("animated")) { - m_keyframeView.removeKeyframe(frame); - // inserting a keyframe touches all animated params - for (int j = 0; j < params.count(); ++j) { - QDomElement f = params.item(j).toElement(); - if (f.attribute(QStringLiteral("type")) != QLatin1String("animated") && f.attribute(QStringLiteral("type")) != QLatin1String("animatedrect")) { - continue; - } - f.setAttribute( - QStringLiteral("value"), - m_keyframeView.serialize(f.attribute(QStringLiteral("name")), f.attribute(QStringLiteral("type")) == QLatin1String("animatedrect"))); - } - } - } - - updateKeyframes(effect); - update(); -} - -bool AbstractClipItem::resizeGeometries(QDomElement effect, int width, int height, int previousDuration, int start, int duration, int cropstart) -{ - QString geom; - bool modified = false; - QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter")); - bool cut = effect.attribute(QStringLiteral("sync_in_out")).toInt() == 1 || effect.tagName() == QLatin1String("transition"); - if (!cut) { - return false; - } - effect.setAttribute(QStringLiteral("in"), QString::number(cropstart)); - effect.setAttribute(QStringLiteral("out"), QString::number(cropstart + duration)); - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - if (!e.isNull() && e.attribute(QStringLiteral("type")) == QLatin1String("geometry")) { - geom = e.attribute(QStringLiteral("value")); - Mlt::Geometry geometry(geom.toUtf8().data(), previousDuration, width, height); - e.setAttribute(QStringLiteral("value"), QString::fromLatin1(geometry.serialise(start, start + duration))); - modified = true; - } - } - return modified; -} - -QString AbstractClipItem::resizeAnimations(QDomElement effect, int previousDuration, int start, int duration, int cropstart) -{ - QString animation; - QString keyframes; - QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - if (!e.isNull() && e.attribute(QStringLiteral("type")) == QLatin1String("animated")) { - animation = e.attribute(QStringLiteral("value")); - if (effect.attribute(QStringLiteral("sync_in_out")) == QLatin1String("1")) { - keyframes = KeyframeView::cutAnimation(animation, start, duration, previousDuration); - effect.setAttribute(QStringLiteral("in"), QString::number(start)); - effect.setAttribute(QStringLiteral("out"), QString::number(start + duration)); - } else { - keyframes = KeyframeView::addBorderKeyframes(animation, cropstart, duration); - } - // TODO: in case of multiple animated params, use _intimeline to detect active one - e.setAttribute(QStringLiteral("value"), keyframes); - } - } - return keyframes; -} - -bool AbstractClipItem::switchKeyframes(QDomElement param, int in, int oldin, int out, int oldout) -{ - QString animation = param.attribute(QStringLiteral("value")); - if (in != oldin) { - animation = KeyframeView::switchAnimation(animation, in, oldin, out, oldout, param.attribute(QStringLiteral("type")) == QLatin1String("animatedrect")); - } - if (out != oldout) { - animation = - KeyframeView::switchAnimation(animation, out, oldout, out, oldout, param.attribute(QStringLiteral("type")) == QLatin1String("animatedrect")); - } - if (animation != param.attribute(QStringLiteral("value"))) { - param.setAttribute(QStringLiteral("value"), animation); - return true; - } - return false; -} diff --git a/src/timeline/abstractclipitem.h b/src/timeline/abstractclipitem.h deleted file mode 100644 index fea188c41..000000000 --- a/src/timeline/abstractclipitem.h +++ /dev/null @@ -1,129 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Marco Gittler (g.marco@freenet.de) * - * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef ABSTRACTCLIPITEM_H -#define ABSTRACTCLIPITEM_H - -#include "definitions.h" -#include "gentime.h" -#include "keyframeview.h" - -#include "mlt++/MltAnimation.h" -#include "mlt++/MltProperties.h" - -#include -#include -#include - -class CustomTrackScene; -class QGraphicsSceneMouseEvent; - -class AbstractClipItem : public QObject, public QGraphicsRectItem -{ - Q_OBJECT - Q_PROPERTY(QRectF rect READ rect WRITE setRect) - Q_PROPERTY(qreal opacity READ opacity WRITE setOpacity) - -public: - AbstractClipItem(const ItemInfo &info, const QRectF &rect, double fps); - virtual ~AbstractClipItem(); - ItemInfo info() const; - CustomTrackScene *projectScene(); - void updateRectGeometry(); - void updateItem(int track); - void setItemLocked(bool locked); - bool isItemLocked() const; - void closeAnimation(); - - virtual OperationType operationMode(const QPointF &pos, Qt::KeyboardModifiers modifiers) = 0; - virtual void updateKeyframes(const QDomElement &effect) = 0; - virtual GenTime startPos() const; - virtual GenTime endPos() const; - virtual int track() const; - virtual GenTime cropStart() const; - virtual GenTime cropDuration() const; - /** @brief Return the current item's height */ - static int itemHeight(); - /** @brief Return the current item's vertical offset - * For example transitions are drawn at 1/3 of track height */ - static int itemOffset(); - - /** @brief Resizes the clip from the start. - * @param posx Absolute position of new in point - * @param hasSizeLimit (optional) Whether the clip has a maximum size */ - virtual void resizeStart(int posx, bool hasSizeLimit = true, bool emitChange = true); - void updateKeyFramePos(int frame, const double y); - int selectedKeyFramePos() const; - int originalKeyFramePos() const; - void prepareKeyframeMove(); - int keyframesCount(); - double editedKeyFrameValue(); - double getKeyFrameClipHeight(const double y); - QAction *parseKeyframeActions(const QList &list); - void editKeyframeType(const QDomElement &effect, int type); - void attachKeyframeToEnd(const QDomElement &effect, bool attach); - bool isAttachedToEnd() const; - - /** @brief Resizes the clip from the end. - * @param posx Absolute position of new out point */ - virtual void resizeEnd(int posx, bool emitChange = true); - virtual double fps() const; - virtual void updateFps(double fps); - virtual GenTime maxDuration() const; - virtual void setCropStart(const GenTime &pos); - - /** @brief Set this clip as the main selected clip (or not). */ - void setMainSelectedClip(bool selected); - /** @brief Is this clip selected as the main clip. */ - bool isMainSelectedClip(); - - void insertKeyframe(QDomElement effect, int pos, double val, bool defaultValue = false); - void movedKeyframe(QDomElement effect, int newpos, int oldpos = -1, double value = -1); - void removeKeyframe(QDomElement effect, int frame); - -private slots: - void doUpdate(const QRectF &r); - void slotSelectItem(); - -protected: - ItemInfo m_info; - GenTime m_maxDuration; - int m_visibleParam; - int m_selectedEffect; - QTimer m_selectionTimer; - double m_fps; - /** @brief True if this is the last clip the user selected */ - bool m_isMainSelectedClip; - KeyframeView m_keyframeView; - - void mousePressEvent(QGraphicsSceneMouseEvent *event) override; - void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; - void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; - int trackForPos(int position); - int posForTrack(int track); - bool resizeGeometries(QDomElement effect, int width, int height, int previousDuration, int start, int duration, int cropstart); - QString resizeAnimations(QDomElement effect, int previousDuration, int start, int duration, int cropstart); - bool switchKeyframes(QDomElement param, int in, int oldin, int out, int oldout); - -signals: - void selectItem(AbstractClipItem *); -}; - -#endif diff --git a/src/timeline/abstractgroupitem.cpp b/src/timeline/abstractgroupitem.cpp deleted file mode 100644 index 5c66536d7..000000000 --- a/src/timeline/abstractgroupitem.cpp +++ /dev/null @@ -1,607 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Marco Gittler (g.marco@freenet.de) * - * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "abstractgroupitem.h" -#include "abstractclipitem.h" -#include "customtrackscene.h" -#include "customtrackview.h" - -#include "kdenlivesettings.h" - -#include -#include -#include -#include -#include - -AbstractGroupItem::AbstractGroupItem(double /* fps */) - : QObject() - , QGraphicsItemGroup() -{ - setZValue(1); - setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIsSelectable); - setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); - setAcceptDrops(true); -} - -int AbstractGroupItem::type() const -{ - return GroupWidget; -} - -int AbstractGroupItem::track() const -{ - // return (int)(scenePos().y() / KdenliveSettings::trackheight()); - int topTrack = -1; - QList children = childItems(); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() == GroupWidget) { - children.append(children.at(i)->childItems()); - continue; - } - AbstractClipItem *item = static_cast(children.at(i)); - if ((item != nullptr) && (topTrack == -1 || topTrack < item->track())) { - topTrack = item->track(); - } - } - return topTrack; -} - -void AbstractGroupItem::setItemLocked(bool locked) -{ - if (locked) { - setSelected(false); - } - - setFlag(QGraphicsItem::ItemIsMovable, !locked); - setFlag(QGraphicsItem::ItemIsSelectable, !locked); - - for (QGraphicsItem *child : childItems()) { - static_cast(child)->setItemLocked(locked); - } -} - -bool AbstractGroupItem::isItemLocked() const -{ - return !(flags() & (QGraphicsItem::ItemIsSelectable)); -} - -CustomTrackScene *AbstractGroupItem::projectScene() -{ - if (scene()) { - return static_cast(scene()); - } - return nullptr; -} - -QPainterPath AbstractGroupItem::clipGroupSpacerShape(const QPointF &offset) const -{ - return spacerGroupShape(AVWidget, offset); -} - -QPainterPath AbstractGroupItem::clipGroupShape(const QPointF &offset) const -{ - return groupShape(AVWidget, offset); -} - -QPainterPath AbstractGroupItem::transitionGroupShape(const QPointF &offset) const -{ - return groupShape(TransitionWidget, offset); -} - -QPainterPath AbstractGroupItem::groupShape(GraphicsRectItem type, const QPointF &offset) const -{ - QPainterPath path; - QList children = childItems(); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() == (int)type) { - QRectF r(children.at(i)->sceneBoundingRect()); - r.translate(offset); - path.addRect(r); - } else if (children.at(i)->type() == GroupWidget) { - QList subchildren = children.at(i)->childItems(); - for (int j = 0; j < subchildren.count(); ++j) { - if (subchildren.at(j)->type() == (int)type) { - QRectF r(subchildren.at(j)->sceneBoundingRect()); - r.translate(offset); - path.addRect(r); - } - } - } - } - return path; -} - -QPainterPath AbstractGroupItem::spacerGroupShape(GraphicsRectItem type, const QPointF &offset) const -{ - QPainterPath path; - QList children = childItems(); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() == (int)type) { - QRectF r(children.at(i)->sceneBoundingRect()); - r.translate(offset); - r.setRight(scene()->width()); - path.addRect(r); - } else if (children.at(i)->type() == GroupWidget) { - QList subchildren = children.at(i)->childItems(); - for (int j = 0; j < subchildren.count(); ++j) { - if (subchildren.at(j)->type() == (int)type) { - QRectF r(subchildren.at(j)->sceneBoundingRect()); - r.translate(offset); - r.setRight(scene()->width()); - path.addRect(r); - } - } - } - } - return path; -} - -void AbstractGroupItem::addItem(QGraphicsItem *item) -{ - addToGroup(item); - item->setFlag(QGraphicsItem::ItemIsMovable, false); -} - -void AbstractGroupItem::removeItem(QGraphicsItem *item) -{ - removeFromGroup(item); -} - -// virtual -void AbstractGroupItem::paint(QPainter *p, const QStyleOptionGraphicsItem *option, QWidget *) -{ - QColor bgcolor(100, 100, 200, 100); - QRectF bound = option->exposedRect.adjusted(0, 0, 1, 1); - p->setClipRect(bound); - p->setBrush(bgcolor); - QPen pen = p->pen(); - pen.setColor(QColor(200, 90, 90)); - pen.setStyle(Qt::DashLine); - pen.setWidthF(0.0); - p->setPen(pen); - QRectF bd = childrenBoundingRect().adjusted(0, 0, 0, 0); - p->drawRect(bd); -} - -int AbstractGroupItem::trackForPos(int position) -{ - int track = 1; - if ((scene() == nullptr) || scene()->views().isEmpty()) { - return track; - } - CustomTrackView *view = static_cast(scene()->views()[0]); - if (view) { - track = view->getTrackFromPos(position); - } - return track; -} - -int AbstractGroupItem::posForTrack(int track) -{ - int pos = 0; - if ((scene() == nullptr) || scene()->views().isEmpty()) { - return pos; - } - CustomTrackView *view = static_cast(scene()->views()[0]); - if (view) { - pos = view->getPositionFromTrack(track); - } - return pos; -} - -// virtual -QVariant AbstractGroupItem::itemChange(GraphicsItemChange change, const QVariant &value) -{ - if (change == QGraphicsItem::ItemSelectedChange) { - if (value.toBool()) { - setZValue(3); - } else { - setZValue(1); - } - } - CustomTrackScene *scene = nullptr; - if (change == ItemPositionChange && parentItem() == nullptr) { - scene = projectScene(); - } - if (scene) { - // calculate new position. - if (scene->isZooming) { - // For some reason, mouse wheel on selected itm sometimes triggered - // a position change event corrupting timeline, so discard it - return pos(); - } - // calculate new position. - const int trackHeight = KdenliveSettings::trackheight(); - QPointF start = sceneBoundingRect().topLeft(); - QPointF newPos = value.toPointF(); - int xpos = projectScene()->getSnapPointForPos((int)(start.x() + newPos.x() - pos().x()), KdenliveSettings::snaptopoints()); - - xpos = qMax(xpos, 0); - newPos.setX((int)(pos().x() + xpos - (int)start.x())); - QList lockedTracks = property("locked_tracks").value>(); - int proposedTrack = trackForPos(property("y_absolute").toInt() + newPos.y()); - // Check if top item is a clip or a transition - int offset = 0; - int topTrack = -1; - QList groupTracks; - QList children = childItems(); - for (int i = 0; i < children.count(); ++i) { - int currentTrack = 0; - if (children.at(i)->type() == AVWidget || children.at(i)->type() == TransitionWidget) { - currentTrack = static_cast(children.at(i))->track(); - if (!groupTracks.contains(currentTrack)) { - groupTracks.append(currentTrack); - } - } else if (children.at(i)->type() == GroupWidget) { - currentTrack = static_cast(children.at(i))->track(); - } else { - continue; - } - if (children.at(i)->type() == AVWidget) { - if (topTrack == -1 || currentTrack >= topTrack) { - offset = 0; - topTrack = currentTrack; - } - } else if (children.at(i)->type() == TransitionWidget) { - if (topTrack == -1 || currentTrack > topTrack) { - offset = (int)(trackHeight / 3 * 2 - 1); - topTrack = currentTrack; - } - } else if (children.at(i)->type() == GroupWidget) { - QList subchildren = children.at(i)->childItems(); - bool clipGroup = false; - for (int j = 0; j < subchildren.count(); ++j) { - if (subchildren.at(j)->type() == AVWidget || subchildren.at(j)->type() == TransitionWidget) { - int subTrack = static_cast(subchildren.at(j))->track(); - if (!groupTracks.contains(subTrack)) { - groupTracks.append(subTrack); - } - clipGroup = true; - } - } - if (clipGroup) { - if (topTrack == -1 || currentTrack >= topTrack) { - offset = 0; - topTrack = currentTrack; - } - } else { - if (topTrack == -1 || currentTrack > topTrack) { - offset = (int)(trackHeight / 3 * 2 - 1); - topTrack = currentTrack; - } - } - } - } - // Check no clip in the group goes outside of existing tracks - int maximumTrack = projectScene()->tracksCount(); - int groupHeight = 0; - for (int i = 0; i < groupTracks.count(); ++i) { - int trackOffset = topTrack - groupTracks.at(i) + 1; - if (trackOffset > groupHeight) { - groupHeight = trackOffset; - } - } - proposedTrack = qBound(groupHeight, proposedTrack, maximumTrack); - int groupOffset = proposedTrack - topTrack; - bool lockAdjust = false; - if (!lockedTracks.isEmpty()) { - for (int i = 0; i < groupTracks.count(); ++i) { - if (lockedTracks.contains(groupTracks.at(i) + groupOffset)) { - newPos.setY(pos().y()); - lockAdjust = true; - break; - } - } - } - if (!lockAdjust) { - newPos.setY(posForTrack(proposedTrack) + offset); - } - // if (newPos == start) return start; - - /*if (newPos.x() < 0) { - // If group goes below 0, adjust position to 0 - return QPointF(pos().x() - start.x(), pos().y()); - }*/ - - QList collidingItems; - QPainterPath shape; - if (projectScene()->editMode() == TimelineMode::NormalEdit) { - shape = clipGroupShape(newPos - pos()); - collidingItems = scene->items(shape, Qt::IntersectsItemShape); - collidingItems.removeAll(this); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() == GroupWidget) { - QList subchildren = children.at(i)->childItems(); - for (int j = 0; j < subchildren.count(); ++j) { - collidingItems.removeAll(subchildren.at(j)); - } - } - collidingItems.removeAll(children.at(i)); - } - } - if (!collidingItems.isEmpty()) { - bool forwardMove = xpos > start.x(); - int cur_offset = 0; - for (int i = 0; i < collidingItems.count(); ++i) { - QGraphicsItem *collision = collidingItems.at(i); - if (collision->type() == AVWidget) { - // Collision - if (newPos.y() != pos().y()) { - // Track change results in collision, restore original position - newPos.setY(pos().y()); - } else { - AbstractClipItem *item = static_cast(collision); - // Determine best pos - QPainterPath clipPath; - clipPath.addRect(item->sceneBoundingRect()); - QPainterPath res = shape.intersected(clipPath); - cur_offset = qMax(cur_offset, (int)(res.boundingRect().width() + 0.5)); - } - break; - } - } - if (forwardMove) { - newPos.setX(newPos.x() - cur_offset); - } else { - newPos.setX(newPos.x() + cur_offset); - } - // If there is still a collision after our position adjust, restore original pos - collidingItems = scene->items(clipGroupShape(newPos - pos()), Qt::IntersectsItemShape); - collidingItems.removeAll(this); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() == GroupWidget) { - QList subchildren = children.at(i)->childItems(); - for (int j = 0; j < subchildren.count(); ++j) { - collidingItems.removeAll(subchildren.at(j)); - } - } - collidingItems.removeAll(children.at(i)); - } - for (int i = 0; i < collidingItems.count(); ++i) - if (collidingItems.at(i)->type() == AVWidget) { - return pos(); - } - } - - if (projectScene()->editMode() == TimelineMode::NormalEdit) { - shape = transitionGroupShape(newPos - pos()); - collidingItems = scene->items(shape, Qt::IntersectsItemShape); - collidingItems.removeAll(this); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() == GroupWidget) { - QList subchildren = children.at(i)->childItems(); - for (int j = 0; j < subchildren.count(); ++j) { - collidingItems.removeAll(subchildren.at(j)); - } - } - collidingItems.removeAll(children.at(i)); - } - } - if (collidingItems.isEmpty()) { - return newPos; - } - bool forwardMove = xpos > start.x(); - int cur_offset = 0; - for (int i = 0; i < collidingItems.count(); ++i) { - QGraphicsItem *collision = collidingItems.at(i); - if (collision->type() == TransitionWidget) { - // Collision - if (newPos.y() != pos().y()) { - // Track change results in collision, restore original position - return pos(); - } - AbstractClipItem *item = static_cast(collision); - // Determine best pos - QPainterPath clipPath; - clipPath.addRect(item->sceneBoundingRect()); - QPainterPath res = shape.intersected(clipPath); - cur_offset = qMax(cur_offset, (int)(res.boundingRect().width() + 0.5)); - } - } - if (cur_offset > 0) { - if (forwardMove) { - newPos.setX(newPos.x() - cur_offset); - } else { - newPos.setX(newPos.x() + cur_offset); - } - // If there is still a collision after our position adjust, restore original pos - collidingItems = scene->items(transitionGroupShape(newPos - pos()), Qt::IntersectsItemShape); - for (int i = 0; i < children.count(); ++i) { - collidingItems.removeAll(children.at(i)); - } - for (int i = 0; i < collidingItems.count(); ++i) - if (collidingItems.at(i)->type() == TransitionWidget) { - return pos(); - } - } - - return newPos; - } - return QGraphicsItemGroup::itemChange(change, value); -} - -// virtual -void AbstractGroupItem::dropEvent(QGraphicsSceneDragDropEvent *event) -{ - QString effects = QString::fromUtf8(event->mimeData()->data(QStringLiteral("kdenlive/effectslist"))); - QDomDocument doc; - doc.setContent(effects, true); - QDomElement e = doc.documentElement(); - e.setAttribute(QStringLiteral("kdenlive_ix"), 0); - CustomTrackView *view = static_cast(scene()->views()[0]); - QPointF dropPos = event->scenePos(); - QList selection = scene()->items(dropPos); - AbstractClipItem *dropChild = nullptr; - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == AVWidget) { - dropChild = static_cast(selection.at(i)); - break; - } - } - if (view) { - view->slotAddGroupEffect(e, this, dropChild); - } -} - -// virtual -void AbstractGroupItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event) -{ - event->setAccepted(event->mimeData()->hasFormat(QStringLiteral("kdenlive/effectslist"))); -} - -void AbstractGroupItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event) -{ - Q_UNUSED(event) -} - -// virtual -void AbstractGroupItem::mousePressEvent(QGraphicsSceneMouseEvent *event) -{ - if ((event->modifiers() & Qt::ShiftModifier) != 0u) { - // User want to do a rectangle selection, so ignore the event to pass it to the view - event->ignore(); - } else { - QList list = scene()->items(event->scenePos()); - // only allow group move if we click over an item in the group - for (const QGraphicsItem *item : list) { - if (item->type() == TransitionWidget || item->type() == AVWidget) { - QGraphicsItem::mousePressEvent(event); - return; - } - } - event->ignore(); - } -} - -// virtual -void AbstractGroupItem::mouseReleaseEvent(QGraphicsSceneMouseEvent *event) -{ - if ((event->modifiers() & Qt::ControlModifier) != 0u) { - // User want to do a rectangle selection, so ignore the event to pass it to the view - event->ignore(); - } else { - QGraphicsItem::mouseReleaseEvent(event); - } -} - -void AbstractGroupItem::mouseMoveEvent(QGraphicsSceneMouseEvent *event) -{ - if (event->buttons() != Qt::LeftButton || ((event->modifiers() & Qt::ControlModifier) != 0u)) { - // User want to do a rectangle selection, so ignore the event to pass it to the view - event->ignore(); - } else { - QGraphicsItem::mouseMoveEvent(event); - } -} - -void AbstractGroupItem::resizeStart(int diff) -{ - QList children = childItems(); - for (int i = 0; i < children.count(); ++i) { - AbstractClipItem *item = static_cast(children.at(i)); - if ((item != nullptr) && item->type() == AVWidget) { - item->resizeStart(diff); - } - } - update(); -} - -void AbstractGroupItem::resizeEnd(int diff) -{ - QList children = childItems(); - for (int i = 0; i < children.count(); ++i) { - AbstractClipItem *item = static_cast(children.at(i)); - if ((item != nullptr) && item->type() == AVWidget) { - item->resizeEnd(diff); - } - } - update(); -} - -GenTime AbstractGroupItem::duration() const -{ - QList children = childItems(); - GenTime start = GenTime(-1.0); - GenTime end = GenTime(); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() != GroupWidget) { - AbstractClipItem *item = static_cast(children.at(i)); - if (item) { - if (start < GenTime() || item->startPos() < start) { - start = item->startPos(); - } - if (item->endPos() > end) { - end = item->endPos(); - } - } - } else { - children << children.at(i)->childItems(); - } - } - return end - start; -} - -GenTime AbstractGroupItem::startPos() const -{ - QList children = childItems(); - GenTime start = GenTime(-1.0); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() != GroupWidget) { - AbstractClipItem *item = static_cast(children.at(i)); - if (item) { - if (start < GenTime() || item->startPos() < start) { - start = item->startPos(); - } - } - } else { - children << children.at(i)->childItems(); - } - } - return start; -} - -QGraphicsItem *AbstractGroupItem::otherClip(QGraphicsItem *item) -{ - QList children = childItems(); - if (children.isEmpty() || children.count() != 2) { - return nullptr; - } - if (children.at(0) == item) { - return children.at(1); - } - return children.at(0); -} - -QList AbstractGroupItem::childClips() const -{ - QList childClips; - QList children = childItems(); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() != GroupWidget) { - AbstractClipItem *item = static_cast(children.at(i)); - childClips << item; - } else { - AbstractGroupItem *grp = static_cast(children.at(i)); - childClips << grp->childClips(); - } - } - return childClips; -} diff --git a/src/timeline/abstractgroupitem.h b/src/timeline/abstractgroupitem.h deleted file mode 100644 index 90e6e7434..000000000 --- a/src/timeline/abstractgroupitem.h +++ /dev/null @@ -1,81 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Marco Gittler (g.marco@freenet.de) * - * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef ABSTRACTGROUPITEM -#define ABSTRACTGROUPITEM - -#include "definitions.h" - -#include -#include - -class CustomTrackScene; -class AbstractClipItem; -class QGraphicsSceneMouseEvent; - -class AbstractGroupItem : public QObject, public QGraphicsItemGroup -{ - Q_OBJECT -public: - explicit AbstractGroupItem(double fps); - int type() const override; - CustomTrackScene *projectScene(); - void addItem(QGraphicsItem *item); - void removeItem(QGraphicsItem *item); - int track() const; - QPainterPath clipGroupShape(const QPointF &offset) const; - QPainterPath clipGroupSpacerShape(const QPointF &offset) const; - QPainterPath transitionGroupShape(const QPointF &offset) const; - void setItemLocked(bool locked); - bool isItemLocked() const; - QList childClips() const; - // ItemInfo info() const; - - /** @brief Resizes all clips in this group from start. - *@param diff Difference to startPos stored in m_resizeInfos */ - void resizeStart(int diff); - /** @brief Resizes all clips in this group from end. - * @param diff Difference to endPos stored in m_resizeInfos */ - void resizeEnd(int diff); - - /** @brief Gets the duration (length) of the group. */ - GenTime duration() const; - /** @brief Gets the start frame of the group. */ - GenTime startPos() const; - QGraphicsItem *otherClip(QGraphicsItem *item); - -protected: - QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; - void paint(QPainter *, const QStyleOptionGraphicsItem *, QWidget *) override; - void dragEnterEvent(QGraphicsSceneDragDropEvent *event) override; - void dragLeaveEvent(QGraphicsSceneDragDropEvent *event) override; - void dropEvent(QGraphicsSceneDragDropEvent *event) override; - void mousePressEvent(QGraphicsSceneMouseEvent *event) override; - void mouseReleaseEvent(QGraphicsSceneMouseEvent *event) override; - void mouseMoveEvent(QGraphicsSceneMouseEvent *event) override; - int trackForPos(int position); - int posForTrack(int track); - -private: - QPainterPath groupShape(GraphicsRectItem type, const QPointF &offset) const; - QPainterPath spacerGroupShape(GraphicsRectItem type, const QPointF &offset) const; -}; - -#endif diff --git a/src/timeline/clip.cpp b/src/timeline/clip.cpp deleted file mode 100644 index 720e9614b..000000000 --- a/src/timeline/clip.cpp +++ /dev/null @@ -1,203 +0,0 @@ -/* - * Kdenlive timeline clip handling MLT producer - * Copyright 2015 Kdenlive team - * Author: Vincent Pinon - * - * This program 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) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * This program 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 this program. If not, see . - * - */ - -#include "clip.h" -#include -#include -#include - -Clip::Clip(Mlt::Producer &producer) - : QObject() - , m_producer(producer) -{ -} - -Clip::Clip(Clip &other) - : QObject() -{ - m_producer = other.producer(); -} - -Clip::~Clip() = default; - -Clip &Clip::operator=(Clip &other) -{ - m_producer = other.producer(); - return *this; -} - -Mlt::Producer &Clip::producer() -{ - return m_producer; -} - -void Clip::setProducer(Mlt::Producer &producer) -{ - m_producer = producer; -} - -void Clip::adjustEffectsLength() -{ - int ct = 0; - Mlt::Filter *filter = m_producer.filter(ct); - while (filter != nullptr) { - if (filter->get_int("kdenlive:sync_in_out") == 1) { - filter->set_in_and_out(m_producer.get_in(), m_producer.get_out()); - } - ct++; - delete filter; - filter = m_producer.filter(ct); - } -} - -void Clip::addEffects(Mlt::Service &service, bool skipFades) -{ - for (int ix = 0; ix < service.filter_count(); ++ix) { - QScopedPointer effect(service.filter(ix)); - // Only duplicate Kdenlive filters, and skip the fade in effects - if (effect->is_valid()) { - QString effectId = QString::fromLatin1(effect->get("kdenlive_id")); - if (effectId.isEmpty() || (skipFades && (effectId == QLatin1String("fadein") || effectId == QLatin1String("fade_from_black")))) { - continue; - } - // no easy filter copy: do it by hand! - auto *copy = new Mlt::Filter(*effect->profile(), effect->get("mlt_service")); - if ((copy != nullptr) && copy->is_valid()) { - for (int i = 0; i < effect->count(); ++i) { - QString paramName = QString::fromLatin1(effect->get_name(i)); - if (paramName == QLatin1String("kdenlive:sync_in_out") && QString::fromLatin1(effect->get(i)) == QLatin1String("1")) { - // Effect in/out must be synced with clip in/out - copy->set_in_and_out(m_producer.get_in(), m_producer.get_out()); - } - if (paramName.at(0) != QLatin1Char('_')) { - copy->set(effect->get_name(i), effect->get(i)); - } - } - m_producer.attach(*copy); - } - delete copy; - } - } -} - -void Clip::replaceEffects(Mlt::Service &service) -{ - // remove effects first - int ct = 0; - Mlt::Filter *filter = m_producer.filter(ct); - while (filter != nullptr) { - QString ix = QString::fromLatin1(filter->get("kdenlive_ix")); - if (!ix.isEmpty()) { - if (m_producer.detach(*filter) == 0) { - } else { - ct++; - } - } else { - ct++; - } - delete filter; - filter = m_producer.filter(ct); - } - addEffects(service); -} - -void Clip::deleteEffects() -{ - // remove effects - int ct = 0; - Mlt::Filter *filter = m_producer.filter(ct); - while (filter != nullptr) { - QString ix = QString::fromLatin1(filter->get("kdenlive_id")); - if (!ix.isEmpty()) { - if (m_producer.detach(*filter) == 0) { - } else { - ct++; - } - } else { - ct++; - } - delete filter; - filter = m_producer.filter(ct); - } -} - -void Clip::disableEffects(bool disable) -{ - int ct = 0; - Mlt::Filter *filter = m_producer.filter(ct); - while (filter != nullptr) { - QString ix = QString::fromLatin1(filter->get("kdenlive_ix")); - if (!ix.isEmpty()) { - if (disable && filter->get_int("disable") == 0) { - filter->set("disable", 1); - filter->set("auto_disable", 1); - } else if (!disable && filter->get_int("auto_disable") == 1) { - filter->set("disable", (char *)nullptr); - filter->set("auto_disable", (char *)nullptr); - } - } - ct++; - delete filter; - filter = m_producer.filter(ct); - } -} - -const QByteArray Clip::xml() -{ - Mlt::Consumer c(*m_producer.profile(), "xml", "string"); - Mlt::Service s(m_producer.get_service()); - int ignore = s.get_int("ignore_points"); - if (ignore != 0) { - s.set("ignore_points", 0); - } - c.connect(s); - c.set("time_format", "frames"); - c.set("no_meta", 1); - c.set("no_root", 1); - c.set("no_profile", 1); - c.set("root", "/"); - c.set("store", "kdenlive"); - c.start(); - if (ignore != 0) { - s.set("ignore_points", ignore); - } - return c.get("string"); -} - -Mlt::Producer *Clip::clone() -{ - QByteArray prodXml = xml(); - Mlt::Producer *clone = new Mlt::Producer(*m_producer.profile(), "xml-string", prodXml); - return clone; -} - -Mlt::Producer *Clip::softClone(const char *list) -{ - QString service = QString::fromLatin1(m_producer.get("mlt_service")); - QString resource = QString::fromLatin1(m_producer.get("resource")); - Mlt::Producer *clone = new Mlt::Producer(*m_producer.profile(), service.toUtf8().constData(), resource.toUtf8().constData()); - Mlt::Properties original(m_producer.get_properties()); - Mlt::Properties cloneProps(clone->get_properties()); - cloneProps.pass_list(original, list); - return clone; -} diff --git a/src/timeline/clip.h b/src/timeline/clip.h deleted file mode 100644 index 4af55431c..000000000 --- a/src/timeline/clip.h +++ /dev/null @@ -1,64 +0,0 @@ -/* - * Kdenlive timeline clip handling MLT producer - * Copyright 2015 Kdenlive team - * Author: Vincent Pinon - * - * This program 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) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * This program 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 this program. If not, see . - * - */ - -#ifndef CLIP_H -#define CLIP_H - -#include -#include -#include - -class Clip : public QObject -{ - Q_OBJECT - Q_PROPERTY(Mlt::Producer producer READ producer WRITE setProducer) - -public: - explicit Clip(Mlt::Producer &producer); - Clip(Clip &other); - ~Clip(); - Clip &operator=(Clip &other); - const QByteArray xml(); - /** @brief: Clone a producer (creates a completely independent copy). */ - Mlt::Producer *clone(); - /** @brief: Clone a producer without using xml-string producer. - * When Movit is used, we must use this because xml-string crashes (probably attaches some normalizers) - */ - Mlt::Producer *softClone(const char *list); - void deleteEffects(); - void addEffects(Mlt::Service &service, bool skipFades = false); - void replaceEffects(Mlt::Service &service); - void delEffect(int index); - /** @brief: Dis/enable all kdenlive effects on a clip. */ - void disableEffects(bool disable); - void adjustEffectsLength(); - Mlt::Producer &producer(); - -public Q_SLOTS: - void setProducer(Mlt::Producer &producer); - -private: - Mlt::Producer m_producer; -}; - -#endif // CLIP_H diff --git a/src/timeline/clipdurationdialog.cpp b/src/timeline/clipdurationdialog.cpp deleted file mode 100644 index 1ec6e6440..000000000 --- a/src/timeline/clipdurationdialog.cpp +++ /dev/null @@ -1,172 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "clipdurationdialog.h" -#include "clipitem.h" - -#include - -#include - -ClipDurationDialog::ClipDurationDialog(AbstractClipItem *clip, const Timecode &tc, const GenTime &min, const GenTime &max, QWidget *parent) - : QDialog(parent) - , m_clip(clip) - , m_min(min) - , m_max(max) -{ - setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); - setupUi(this); - - m_pos = new TimecodeDisplay(tc); - m_cropStart = new TimecodeDisplay(tc); - m_dur = new TimecodeDisplay(tc); - m_cropEnd = new TimecodeDisplay(tc); - - clip_position_box->addWidget(m_pos); - crop_start_box->addWidget(m_cropStart); - clip_duration_box->addWidget(m_dur); - crop_end_box->addWidget(m_cropEnd); - - bool allowCrop = true; - if (clip->type() == AVWidget) { - ClipItem *item = static_cast(clip); - const int t = item->clipType(); - if (t == Color || t == Image || t == Text) { - allowCrop = false; - } - } - - if (!allowCrop || clip->type() == TransitionWidget) { - m_cropStart->setHidden(true); - crop_label->hide(); - m_cropEnd->setHidden(true), end_label->hide(); - } - - m_crop = m_clip->cropStart(); - - m_pos->setValue(m_clip->startPos()); - m_dur->setValue(m_clip->cropDuration()); - m_cropStart->setValue(m_clip->cropStart()); - m_cropEnd->setValue(m_clip->maxDuration() - m_clip->cropDuration() - m_clip->cropStart()); - - connect(m_pos, &TimecodeDisplay::timeCodeEditingFinished, this, &ClipDurationDialog::slotCheckStart); - connect(m_dur, &TimecodeDisplay::timeCodeEditingFinished, this, &ClipDurationDialog::slotCheckDuration); - connect(m_cropStart, &TimecodeDisplay::timeCodeEditingFinished, this, &ClipDurationDialog::slotCheckCrop); - connect(m_cropEnd, &TimecodeDisplay::timeCodeEditingFinished, this, &ClipDurationDialog::slotCheckEnd); - - adjustSize(); -} - -ClipDurationDialog::~ClipDurationDialog() -{ - delete m_pos; - delete m_dur; - delete m_cropStart; - delete m_cropEnd; -} - -void ClipDurationDialog::slotCheckStart() -{ - GenTime start = m_pos->gentime(); - GenTime duration = m_dur->gentime(); - if (m_min != GenTime() && start < m_min) { - m_pos->setValue(m_min); - } else if (m_max != GenTime() && start + duration > m_max) { - m_pos->setValue(m_max - duration); - } -} - -void ClipDurationDialog::slotCheckDuration() -{ - GenTime start = m_pos->gentime(); - GenTime duration = m_dur->gentime(); - GenTime cropStart = m_cropStart->gentime(); - GenTime maxDuration; - - if (m_clip->maxDuration() == GenTime()) { - maxDuration = m_max; - } else { - maxDuration = m_max == GenTime() ? start + m_clip->maxDuration() - cropStart : qMin(m_max, start + m_clip->maxDuration() - cropStart); - } - - if (maxDuration != GenTime() && start + duration > maxDuration) { - m_dur->blockSignals(true); - m_dur->setValue(maxDuration - start); - m_dur->blockSignals(false); - } - - m_cropEnd->blockSignals(true); - m_cropEnd->setValue(m_clip->maxDuration() - m_dur->gentime() - cropStart); - m_cropEnd->blockSignals(false); -} - -void ClipDurationDialog::slotCheckCrop() -{ - GenTime duration = m_dur->gentime(); - GenTime cropStart = m_cropStart->gentime(); - GenTime maxDuration = m_clip->maxDuration(); - - GenTime diff = cropStart - m_crop; - if ((diff > GenTime() && diff < duration) || diff < GenTime()) { - duration -= diff; - } else { - m_cropStart->setValue(m_crop); - return; - } - - if (maxDuration != GenTime() && cropStart + duration > maxDuration) { - m_cropStart->setValue(m_crop); - } else { - m_crop = cropStart; - m_dur->blockSignals(true); - m_dur->setValue(duration); - m_dur->blockSignals(false); - } -} - -void ClipDurationDialog::slotCheckEnd() -{ - GenTime cropStart = m_cropStart->gentime(); - GenTime cropEnd = m_cropEnd->gentime(); - GenTime duration = m_clip->maxDuration() - cropEnd - cropStart; - - if (duration >= GenTime()) { - m_dur->setValue(duration); - slotCheckDuration(); - } else { - m_cropEnd->blockSignals(true); - m_cropEnd->setValue(m_clip->maxDuration() - m_dur->gentime() - cropStart); - m_cropEnd->blockSignals(false); - } -} - -GenTime ClipDurationDialog::startPos() const -{ - return m_pos->gentime(); -} - -GenTime ClipDurationDialog::cropStart() const -{ - return m_cropStart->gentime(); -} - -GenTime ClipDurationDialog::duration() const -{ - return m_dur->gentime(); -} diff --git a/src/timeline/clipdurationdialog.h b/src/timeline/clipdurationdialog.h deleted file mode 100644 index 5e4656f8f..000000000 --- a/src/timeline/clipdurationdialog.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef CLIPDURATIONDIALOG_H -#define CLIPDURATIONDIALOG_H - -#include "timeline/abstractclipitem.h" - -#include "timecodedisplay.h" -#include "ui_clipdurationdialog_ui.h" - -/** - * @class ClipDurationDialog - * @brief A dialog for modifying an item's (clip or transition) duration. - * @author Jean-Baptiste Mardelle - */ - -class ClipDurationDialog : public QDialog, public Ui::ClipDurationDialog_UI -{ - Q_OBJECT - -public: - explicit ClipDurationDialog(AbstractClipItem *clip, const Timecode &tc, const GenTime &min, const GenTime &max, QWidget *parent = nullptr); - ~ClipDurationDialog(); - GenTime startPos() const; - GenTime cropStart() const; - GenTime duration() const; - -private slots: - void slotCheckDuration(); - void slotCheckStart(); - void slotCheckCrop(); - void slotCheckEnd(); - -private: - AbstractClipItem *m_clip; - TimecodeDisplay *m_pos; - TimecodeDisplay *m_dur; - TimecodeDisplay *m_cropStart; - TimecodeDisplay *m_cropEnd; - GenTime m_min; - GenTime m_max; - GenTime m_crop; -}; - -#endif diff --git a/src/timeline/clipitem.cpp b/src/timeline/clipitem.cpp deleted file mode 100644 index d32a66148..000000000 --- a/src/timeline/clipitem.cpp +++ /dev/null @@ -1,1728 +0,0 @@ - -/*************************************************************************** - * Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "clipitem.h" -#include "abstractgroupitem.h" -#include "customtrackscene.h" -#include "customtrackview.h" -#include "transition.h" - -#include "bin/projectclip.h" -#include "doc/kthumb.h" -#include "kdenlivesettings.h" -#include "mltcontroller/effectscontroller.h" -#include "renderer.h" -#include "utils/KoIconUtils.h" - -#include "kdenlive_debug.h" -#include -#include -#include -#include -#include -#include - -static int FRAME_SIZE; - -ClipItem::ClipItem(ProjectClip *clip, const ItemInfo &info, double fps, double speed, int strobe, int frame_width, bool generateThumbs) - : AbstractClipItem(info, QRectF(), fps) - , m_binClip(clip) - , m_startFade(0) - , m_endFade(0) - , m_clipState(PlaylistState::Original) - , m_originalClipState(PlaylistState::Original) - , m_startPix(QPixmap()) - , m_endPix(QPixmap()) - , m_hasThumbs(false) - , m_timeLine(nullptr) - , m_startThumbRequested(false) - , m_endThumbRequested(false) - , - // m_hover(false), - m_speed(speed) - , m_strobe(strobe) - , m_framePixelWidth(0) -{ - setZValue(2); - m_effectList = EffectsList(true); - FRAME_SIZE = frame_width; - setRect(0, 0, (info.endPos - info.startPos).frames(m_fps) - 0.02, (double)itemHeight()); - // set speed independent info - if (m_speed <= 0 && m_speed > -1) { - m_speed = -1.0; - } - m_speedIndependantInfo = m_info; - m_speedIndependantInfo.cropStart = GenTime((int)(m_info.cropStart.frames(m_fps) * qAbs(m_speed)), m_fps); - m_speedIndependantInfo.cropDuration = GenTime((int)(m_info.cropDuration.frames(m_fps) * qAbs(m_speed)), m_fps); - - m_clipType = m_binClip->clipType(); - // m_cropStart = info.cropStart; - if (m_binClip->hasLimitedDuration()) { - m_maxDuration = m_binClip->duration(); - } else { - // For color / image / text clips, we have unlimited duration - m_maxDuration = GenTime(); - } - setAcceptDrops(true); - m_audioThumbReady = m_binClip->audioThumbCreated(); - // setAcceptsHoverEvents(true); - connect(m_binClip, &ProjectClip::refreshClipDisplay, this, &ClipItem::slotRefreshClip); - if (m_clipType == AV || m_clipType == Video || m_clipType == SlideShow || m_clipType == Playlist) { - m_baseColor = QColor(141, 166, 215); - if (m_binClip->isReady()) { - m_hasThumbs = true; - m_startThumbTimer.setSingleShot(true); - connect(&m_startThumbTimer, &QTimer::timeout, this, &ClipItem::slotGetStartThumb); - m_endThumbTimer.setSingleShot(true); - connect(&m_endThumbTimer, &QTimer::timeout, this, &ClipItem::slotGetEndThumb); - connect(m_binClip, SIGNAL(thumbReady(int, QImage)), this, SLOT(slotThumbReady(int, QImage))); - if (generateThumbs && KdenliveSettings::videothumbnails()) { - QTimer::singleShot(0, this, &ClipItem::slotFetchThumbs); - } - } - } else if (m_clipType == Color) { - m_baseColor = m_binClip->getProducerColorProperty(QStringLiteral("resource")); - } else if (m_clipType == Image || m_clipType == Text || m_clipType == QText || m_clipType == TextTemplate) { - m_baseColor = QColor(141, 166, 215); - m_startPix = m_binClip->thumbnail(frame_width, rect().height()); - //connect(m_binClip, SIGNAL(thumbUpdated(QImage)), this, SLOT(slotUpdateThumb(QImage))); - // connect(m_clip->thumbProducer(), SIGNAL(thumbReady(int,QImage)), this, SLOT(slotThumbReady(int,QImage))); - } else if (m_clipType == Audio) { - m_baseColor = QColor(141, 215, 166); - } - //connect(m_binClip, &ProjectClip::gotAudioData, this, &ClipItem::slotGotAudioData); - m_paintColor = m_baseColor; -} - -ClipItem::~ClipItem() -{ - blockSignals(true); - m_endThumbTimer.stop(); - m_startThumbTimer.stop(); - if (scene()) { - scene()->removeItem(this); - } - // if (m_clipType == Video | AV | SlideShow | Playlist) { // WRONG, cannot use | - // disconnect(m_clip->thumbProducer(), SIGNAL(thumbReady(int,QImage)), this, SLOT(slotThumbReady(int,QImage))); - // disconnect(m_clip, SIGNAL(gotAudioData()), this, SLOT(slotGotAudioData())); - //} - delete m_timeLine; -} - -ClipItem *ClipItem::clone(const ItemInfo &info) const -{ - auto *duplicate = new ClipItem(m_binClip, info, m_fps, m_speed, m_strobe, FRAME_SIZE); - duplicate->setPos(pos()); - if (m_clipType == Image || m_clipType == Text || m_clipType == TextTemplate) { - duplicate->slotSetStartThumb(m_startPix); - } else if (m_clipType != Color && m_clipType != QText) { - if (info.cropStart == m_info.cropStart) { - duplicate->slotSetStartThumb(m_startPix); - } - if (info.cropStart + (info.endPos - info.startPos) == m_info.cropStart + m_info.cropDuration) { - duplicate->slotSetEndThumb(m_endPix); - } - } - duplicate->setEffectList(m_effectList); - duplicate->setState(m_clipState); - duplicate->setFades(fadeIn(), fadeOut()); - // duplicate->setSpeed(m_speed); - return duplicate; -} - -void ClipItem::setEffectList(const EffectsList &effectList) -{ - m_effectList.clone(effectList); - m_effectNames = m_effectList.effectNames().join(QStringLiteral(" / ")); - m_startFade = 0; - m_endFade = 0; - if (!m_effectList.isEmpty()) { - // If we only have one fade in /ou effect, always display it in timeline - for (int i = 0; i < m_effectList.count(); ++i) { - bool startFade = false; - bool endFade = false; - QDomElement effect = m_effectList.at(i); - QString effectId = effect.attribute(QStringLiteral("id")); - // check if it is a fade effect - int fade = 0; - if (effectId == QLatin1String("fadein") || effectId == QLatin1String("fade_from_black")) { - fade = EffectsList::parameter(effect, QStringLiteral("out")).toInt() - EffectsList::parameter(effect, QStringLiteral("in")).toInt(); - startFade = true; - } else if (effectId == QLatin1String("fadeout") || effectId == QLatin1String("fade_to_black")) { - fade = EffectsList::parameter(effect, QStringLiteral("in")).toInt() - EffectsList::parameter(effect, QStringLiteral("out")).toInt(); - endFade = true; - } - if (fade > 0) { - if (!startFade) { - m_startFade = fade; - } else { - m_startFade = 0; - } - } else if (fade < 0) { - if (!endFade) { - m_endFade = -fade; - } else { - m_endFade = 0; - } - } - } - setSelectedEffect(1); - } -} - -const EffectsList ClipItem::effectList() const -{ - return m_effectList; -} - -int ClipItem::selectedEffectIndex() const -{ - return m_selectedEffect; -} - -void ClipItem::initEffect(const QDomElement &effect, int diff, int offset) -{ - EffectsController::initEffect(m_info, m_effectList, m_binClip->getProducerProperty(QStringLiteral("proxy")), effect, diff, offset); -} - -bool ClipItem::checkKeyFrames(int width, int height, int previousDuration, int cutPos) -{ - bool clipEffectsModified = false; - int effectsCount = m_effectList.count(); - if (effectsCount == 0) { - // reset keyframes - m_keyframeView.reset(); - } - // go through all effects this clip has - for (int ix = 0; ix < effectsCount; ++ix) { - // Check geometry params - QDomElement effect = m_effectList.at(ix); - clipEffectsModified = - resizeGeometries(effect, width, height, previousDuration, cutPos == -1 ? 0 : cutPos, cropDuration().frames(m_fps) - 1, cropStart().frames(m_fps)); - QString newAnimation = - resizeAnimations(effect, previousDuration, cutPos == -1 ? 0 : cutPos, cropDuration().frames(m_fps) - 1, cropStart().frames(m_fps)); - if (!newAnimation.isEmpty()) { - // setKeyframes(ix, newAnimation.split(QLatin1Char(';'), QString::SkipEmptyParts)); - clipEffectsModified = true; - } - if (clipEffectsModified) { - setKeyframes(ix); - continue; - } - } - return clipEffectsModified; -} - -void ClipItem::setKeyframes(const int ix) -{ - QDomElement effect = m_effectList.at(ix); - if (effect.attribute(QStringLiteral("disable")) == QLatin1String("1")) { - return; - } - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - - if (m_keyframeView.loadKeyframes(locale, effect, cropStart().frames(m_fps), cropDuration().frames(m_fps))) { - // Keyframable effect found - update(); - } -} - -void ClipItem::setSelectedEffect(const int ix) -{ - int editedKeyframe = -1; - if (m_selectedEffect == ix) { - // reloading same effect, keep current keyframe reference - editedKeyframe = m_keyframeView.activeKeyframe; - } - m_selectedEffect = ix; - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - QDomElement effect = effectAtIndex(m_selectedEffect); - bool refreshClip = false; - m_keyframeView.reset(); - if (!effect.isNull() && effect.attribute(QStringLiteral("disable")) != QLatin1String("1")) { - QString effectId = effect.attribute(QStringLiteral("id")); - - // Check for fades to display in timeline - int startFade1 = m_effectList.hasEffect(QString(), QStringLiteral("fadein")); - int startFade2 = m_effectList.hasEffect(QString(), QStringLiteral("fade_from_black")); - - if (startFade1 >= 0 && startFade2 >= 0) { - // We have 2 fade ins, only display if effect is selected - if (ix == startFade1 || ix == startFade2) { - m_startFade = EffectsList::parameter(effect, QStringLiteral("out")).toInt() - EffectsList::parameter(effect, QStringLiteral("in")).toInt(); - refreshClip = true; - } else { - m_startFade = 0; - refreshClip = true; - } - } else if (startFade1 >= 0 || startFade2 >= 0) { - int current = qMax(startFade1, startFade2); - QDomElement fade = effectAtIndex(current); - m_startFade = EffectsList::parameter(fade, QStringLiteral("out")).toInt() - EffectsList::parameter(fade, QStringLiteral("in")).toInt(); - refreshClip = true; - } - - // Check for fades out to display in timeline - int endFade1 = m_effectList.hasEffect(QString(), QStringLiteral("fadeout")); - int endFade2 = m_effectList.hasEffect(QString(), QStringLiteral("fade_to_black")); - - if (endFade1 >= 0 && endFade2 >= 0) { - // We have 2 fade ins, only display if effect is selected - if (ix == endFade1 || ix == endFade2) { - m_endFade = EffectsList::parameter(effect, QStringLiteral("out")).toInt() - EffectsList::parameter(effect, QStringLiteral("in")).toInt(); - refreshClip = true; - } else { - m_endFade = 0; - refreshClip = true; - } - } else if (endFade1 >= 0 || endFade2 >= 0) { - int current = qMax(endFade1, endFade2); - QDomElement fade = effectAtIndex(current); - m_endFade = EffectsList::parameter(fade, QStringLiteral("out")).toInt() - EffectsList::parameter(fade, QStringLiteral("in")).toInt(); - refreshClip = true; - } - if (m_keyframeView.loadKeyframes(locale, effect, cropStart().frames(m_fps), cropDuration().frames(m_fps)) && !refreshClip) { - if (editedKeyframe >= 0) { - m_keyframeView.activeKeyframe = editedKeyframe; - } - update(); - return; - } - } - - if (refreshClip) { - update(); - } -} - -QStringList ClipItem::keyframes(const int index) -{ - QStringList result; - QDomElement effect = m_effectList.at(index); - QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter")); - - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - if (e.isNull()) { - continue; - } - if (e.attribute(QStringLiteral("type")) == QLatin1String("keyframe") || e.attribute(QStringLiteral("type")) == QLatin1String("simplekeyframe")) { - result.append(e.attribute(QStringLiteral("keyframes"))); - } - /*else if (e.attribute(QStringLiteral("type")) == QLatin1String("animated")) - result.append(e.attribute(QStringLiteral("value")));*/ - } - return result; -} - -QDomElement ClipItem::selectedEffect() -{ - if (m_selectedEffect == -1 || m_effectList.isEmpty()) { - return QDomElement(); - } - return effectAtIndex(m_selectedEffect); -} - -void ClipItem::resetThumbs(bool clearExistingThumbs) -{ - if (m_clipType == Image || m_clipType == Text || m_clipType == QText || m_clipType == Color || m_clipType == Audio || m_clipType == TextTemplate) { - // These clip thumbnails are linked to bin thumbnail, not dynamic, nothing to do - return; - } - if (clearExistingThumbs) { - m_startPix = QPixmap(); - m_endPix = QPixmap(); - m_audioThumbCachePic.clear(); - } - slotFetchThumbs(); -} - -void ClipItem::refreshClip(bool checkDuration, bool forceResetThumbs) -{ - if (checkDuration && m_binClip->hasLimitedDuration() && (m_maxDuration != m_binClip->duration())) { - m_maxDuration = m_binClip->duration(); - if (m_clipType != Image && m_clipType != Text && m_clipType != QText && m_clipType != Color && m_clipType != TextTemplate) { - if (m_maxDuration != GenTime() && m_info.cropStart + m_info.cropDuration > m_maxDuration) { - // Clip duration changed, make sure to stay in correct range - if (m_info.cropStart > m_maxDuration) { - m_info.cropStart = GenTime(); - m_info.cropDuration = qMin(m_info.cropDuration, m_maxDuration); - } else { - m_info.cropDuration = m_maxDuration; - } - updateRectGeometry(); - } - } - } - if (m_clipType == Color) { - m_baseColor = m_binClip->getProducerColorProperty(QStringLiteral("resource")); - m_paintColor = m_baseColor; - update(); - } else if (KdenliveSettings::videothumbnails()) { - resetThumbs(forceResetThumbs); - } -} - -void ClipItem::slotFetchThumbs() -{ - if (scene() == nullptr || m_clipType == Audio || m_clipType == Color) { - return; - } - if (m_clipType == Image || m_clipType == Text || m_clipType == QText || m_clipType == TextTemplate) { - if (m_startPix.isNull()) { - slotGetStartThumb(); - } - return; - } - - QList frames; - if (m_startPix.isNull()) { - m_startThumbRequested = true; - frames.append((int)m_speedIndependantInfo.cropStart.frames(m_fps)); - } - - if (m_endPix.isNull()) { - m_endThumbRequested = true; - frames.append((int)(m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1); - } - - if (!frames.isEmpty()) { - m_binClip->slotExtractImage(frames); - } -} - -void ClipItem::stopThumbs() -{ - // Clip is about to be deleted, make sure we don't request thumbnails - disconnect(&m_startThumbTimer, &QTimer::timeout, this, &ClipItem::slotGetStartThumb); - disconnect(&m_endThumbTimer, &QTimer::timeout, this, &ClipItem::slotGetEndThumb); -} - -void ClipItem::slotGetStartThumb() -{ - m_startThumbRequested = true; - m_binClip->slotExtractImage(QList() << (int)m_speedIndependantInfo.cropStart.frames(m_fps)); -} - -void ClipItem::slotGetEndThumb() -{ - m_endThumbRequested = true; - m_binClip->slotExtractImage(QList() << (int)(m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1); -} - -void ClipItem::slotSetStartThumb(const QImage &img) -{ - if (!img.isNull() && img.format() == QImage::Format_ARGB32) { - QPixmap pix = QPixmap::fromImage(img); - m_startPix = pix; - QRectF r = boundingRect(); - double width = FRAME_SIZE / projectScene()->scale().x() * projectScene()->scale().y(); - r.setRight(r.left() + width + 2); - update(r); - } -} - -void ClipItem::slotSetEndThumb(const QImage &img) -{ - if (!img.isNull() && img.format() == QImage::Format_ARGB32) { - QPixmap pix = QPixmap::fromImage(img); - m_endPix = pix; - QRectF r = boundingRect(); - double width = FRAME_SIZE / projectScene()->scale().x() * projectScene()->scale().y(); - r.setLeft(r.right() - width - 2); - update(r); - } -} - -void ClipItem::slotThumbReady(int frame, const QImage &img) -{ - if (scene() == nullptr) { - return; - } - if (m_startThumbRequested && frame == m_speedIndependantInfo.cropStart.frames(m_fps)) { - QRectF r = boundingRect(); - QPixmap pix = QPixmap::fromImage(img); - double width = FRAME_SIZE / projectScene()->scale().x() * projectScene()->scale().y(); - m_startPix = pix; - m_startThumbRequested = false; - update(r.left(), r.top(), width, r.height()); - if (m_clipType == Image || m_clipType == Text || m_clipType == QText || m_clipType == TextTemplate) { - update(r.right() - width, r.top(), width, pix.height()); - } - } else if (m_endThumbRequested && frame == (m_speedIndependantInfo.cropStart + m_speedIndependantInfo.cropDuration).frames(m_fps) - 1) { - QRectF r = boundingRect(); - QPixmap pix = QPixmap::fromImage(img); - double width = FRAME_SIZE / projectScene()->scale().x() * projectScene()->scale().y(); - m_endPix = pix; - m_endThumbRequested = false; - update(r.right() - width, r.top(), width, r.height()); - } else if (projectScene()->scale().x() == FRAME_SIZE) { - // We are in full zoom, each frame should be painted - update(); - } -} - -void ClipItem::slotSetStartThumb(const QPixmap &pix) -{ - m_startPix = pix; -} - -void ClipItem::slotSetEndThumb(const QPixmap &pix) -{ - m_endPix = pix; -} - -QPixmap ClipItem::startThumb() const -{ - return m_startPix; -} - -QPixmap ClipItem::endThumb() const -{ - return m_endPix; -} - -void ClipItem::slotGotAudioData() -{ - m_audioThumbReady = true; - if (m_clipType == AV && m_clipState != PlaylistState::AudioOnly) { - QRectF r = boundingRect(); - r.setTop(r.top() + r.height() / 2 - 1); - update(r); - } else { - update(); - } -} - -int ClipItem::type() const -{ - return AVWidget; -} - -QDomElement ClipItem::xml() const -{ - return itemXml(); -} - -QDomElement ClipItem::itemXml() const -{ - QDomDocument doc; - QDomElement xml = m_binClip->toXml(doc); - if (m_speed != 1.0) { - xml.setAttribute(QStringLiteral("speed"), m_speed); - } - if (m_strobe > 1) { - xml.setAttribute(QStringLiteral("strobe"), m_strobe); - } - if (m_clipState == PlaylistState::AudioOnly) { - xml.setAttribute(QStringLiteral("audio_only"), 1); - } else if (m_clipState == PlaylistState::VideoOnly) { - xml.setAttribute(QStringLiteral("video_only"), 1); - } - return doc.documentElement(); -} - -ClipType ClipItem::clipType() const -{ - return m_clipType; -} - -QString ClipItem::clipName() const -{ - if (m_speed == 1.0) { - return m_binClip->name(); - } - return m_binClip->name() + QStringLiteral(" - ") + QString::number(m_speed * 100, 'f', 0) + QLatin1Char('%'); -} - -void ClipItem::flashClip() -{ - if (m_timeLine == nullptr) { - m_timeLine = new QTimeLine(500, this); - m_timeLine->setUpdateInterval(80); - m_timeLine->setCurveShape(QTimeLine::EaseInOutCurve); - m_timeLine->setFrameRange(0, 100); - connect(m_timeLine, &QTimeLine::valueChanged, this, &ClipItem::animate); - } - m_timeLine->start(); -} - -void ClipItem::animate(qreal /*value*/) -{ - QRectF r = boundingRect(); - // r.setHeight(20); - update(r); -} - -// virtual -void ClipItem::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) -{ -} - -const QString &ClipItem::getBinId() const -{ - /* - return m_binClip->clipId(); - */ - return QString(); -} - -const QString ClipItem::getBinHash() const -{ - return m_binClip->hash(); -} - -ProjectClip *ClipItem::binClip() const -{ - return m_binClip; -} - -OperationType ClipItem::operationMode(const QPointF &pos, Qt::KeyboardModifiers modifiers) -{ - if (isItemLocked()) { - return None; - } - // Position is relative to item - const double scale = projectScene()->scale().x(); - double maximumOffset = 8 / scale; - if (isSelected() || ((parentItem() != nullptr) && parentItem()->isSelected())) { - int kf = m_keyframeView.mouseOverKeyFrames(rect(), pos, scale); - if (kf != -1) { - return KeyFrame; - } - } - QRectF rect = sceneBoundingRect(); - int addtransitionOffset = 10; - // Don't allow add transition if track height is very small. No transitions for audio only clips - if (rect.height() < 30 || m_clipState == PlaylistState::AudioOnly || m_clipType == Audio) { - addtransitionOffset = 0; - } - if (qAbs((int)(pos.x() - m_startFade)) < maximumOffset && qAbs((int)(pos.y()) < 10)) { - return FadeIn; - } - if ((pos.x() <= rect.width() / 2) && pos.x() < maximumOffset && (rect.height() - pos.y() > addtransitionOffset)) { - // If we are in a group, allow resize only if all clips start at same position - if ((modifiers & Qt::ControlModifier) != 0u) { - return ResizeStart; - } - if (parentItem()) { - QGraphicsItemGroup *dragGroup = static_cast(parentItem()); - QList list = dragGroup->childItems(); - for (int i = 0; i < list.count(); ++i) { - if (list.at(i)->type() == AVWidget) { - ClipItem *c = static_cast(list.at(i)); - if (c->startPos() != startPos()) { - return MoveOperation; - } - } - } - } - return ResizeStart; - } - if (qAbs((int)(pos.x() - (rect.width() - m_endFade))) < maximumOffset && qAbs((int)(pos.y())) < 10) { - return FadeOut; - } else if ((pos.x() >= rect.width() / 2) && (rect.width() - pos.x() < maximumOffset) && (rect.height() - pos.y() > addtransitionOffset)) { - if ((modifiers & Qt::ControlModifier) != 0u) { - return ResizeEnd; - } - // If we are in a group, allow resize only if all clips end at same position - if (parentItem()) { - QGraphicsItemGroup *dragGroup = static_cast(parentItem()); - QList list = dragGroup->childItems(); - for (int i = 0; i < list.count(); ++i) { - if (list.at(i)->type() == AVWidget) { - ClipItem *c = static_cast(list.at(i)); - if (c->endPos() != endPos()) { - return MoveOperation; - } - } - } - } - return ResizeEnd; - } else if ((pos.x() < maximumOffset) && (rect.height() - pos.y() <= addtransitionOffset)) { - return TransitionStart; - } else if ((rect.width() - pos.x() < maximumOffset) && (rect.height() - pos.y() <= addtransitionOffset)) { - return TransitionEnd; - } - - return MoveOperation; -} - -int ClipItem::itemHeight() -{ - return KdenliveSettings::trackheight() - 2; -} - -void ClipItem::resetFrameWidth(int width) -{ - FRAME_SIZE = width; - update(); -} - -QList ClipItem::snapMarkers(const QList &markers) const -{ - QList snaps; - GenTime pos; - - for (int i = 0; i < markers.size(); ++i) { - pos = GenTime((int)(markers.at(i).frames(m_fps) / qAbs(m_speed) + 0.5), m_fps) - cropStart(); - if (pos > GenTime()) { - if (pos > cropDuration()) { - break; - } else { - snaps.append(pos + startPos()); - } - } - } - return snaps; -} - -QList ClipItem::commentedSnapMarkers() const -{ - QList snaps; - return snaps; -} - -int ClipItem::fadeIn() const -{ - return m_startFade; -} - -int ClipItem::fadeOut() const -{ - return m_endFade; -} - -void ClipItem::setFadeIn(int pos) -{ - if (pos == m_startFade) { - return; - } - int oldIn = m_startFade; - m_startFade = qBound(0, pos, (int)cropDuration().frames(m_fps)); - QRectF rect = boundingRect(); - update(rect.x(), rect.y(), qMax(oldIn, m_startFade), rect.height()); -} - -void ClipItem::setFadeOut(int pos) -{ - if (pos == m_endFade) { - return; - } - int oldOut = m_endFade; - m_endFade = qBound(0, pos, (int)cropDuration().frames(m_fps)); - QRectF rect = boundingRect(); - update(rect.x() + rect.width() - qMax(oldOut, m_endFade), rect.y(), qMax(oldOut, m_endFade), rect.height()); -} - -void ClipItem::setFades(int in, int out) -{ - m_startFade = in; - m_endFade = out; -} - -/* -//virtual -void ClipItem::hoverEnterEvent(QGraphicsSceneHoverEvent *e) -{ - //if (e->pos().x() < 20) m_hover = true; - return; - if (isItemLocked()) return; - m_hover = true; - QRectF r = boundingRect(); - double width = 35 / projectScene()->scale().x(); - double height = r.height() / 2; - //WARNING: seems like it generates a full repaint of the clip, maybe not so good... - update(r.x(), r.y() + height, width, height); - update(r.right() - width, r.y() + height, width, height); -} - -//virtual -void ClipItem::hoverLeaveEvent(QGraphicsSceneHoverEvent *) -{ - if (isItemLocked()) return; - m_hover = false; - QRectF r = boundingRect(); - double width = 35 / projectScene()->scale().x(); - double height = r.height() / 2; - //WARNING: seems like it generates a full repaint of the clip, maybe not so good... - update(r.x(), r.y() + height, width, height); - update(r.right() - width, r.y() + height, width, height); -} -*/ - -void ClipItem::resizeStart(int posx, bool /*size*/, bool emitChange) -{ - bool sizeLimit = false; - if (clipType() != Image && clipType() != Color && clipType() != Text && clipType() != QText && m_clipType != TextTemplate) { - const int min = (startPos() - cropStart()).frames(m_fps); - if (posx < min) { - posx = min; - } - sizeLimit = true; - } - - if (posx == startPos().frames(m_fps)) { - return; - } - const int previous = cropStart().frames(m_fps); - AbstractClipItem::resizeStart(posx, sizeLimit); - - // set speed independent info - m_speedIndependantInfo = m_info; - m_speedIndependantInfo.cropStart = GenTime((int)(m_info.cropStart.frames(m_fps) * qAbs(m_speed)), m_fps); - m_speedIndependantInfo.cropDuration = GenTime((int)(m_info.cropDuration.frames(m_fps) * qAbs(m_speed)), m_fps); - if ((int)cropStart().frames(m_fps) != previous) { - if (m_hasThumbs && KdenliveSettings::videothumbnails()) { - m_startThumbTimer.start(150); - } - } - if (emitChange) { - slotUpdateRange(); - } -} - -void ClipItem::slotUpdateRange() -{ - if (m_isMainSelectedClip) { - emit updateRange(); - } -} - -void ClipItem::resizeEnd(int posx, bool emitChange) -{ - const int max = (startPos() - cropStart() + maxDuration()).frames(m_fps); - if (posx > max && maxDuration() != GenTime()) { - posx = max; - } - if (posx == endPos().frames(m_fps)) { - return; - } - const int previous = cropDuration().frames(m_fps); - AbstractClipItem::resizeEnd(posx); - - // set speed independent info - m_speedIndependantInfo = m_info; - m_speedIndependantInfo.cropStart = GenTime((int)(m_info.cropStart.frames(m_fps) * qAbs(m_speed)), m_fps); - m_speedIndependantInfo.cropDuration = GenTime((int)(m_info.cropDuration.frames(m_fps) * qAbs(m_speed)), m_fps); - - if ((int)cropDuration().frames(m_fps) != previous) { - if (m_hasThumbs && KdenliveSettings::videothumbnails()) { - m_endThumbTimer.start(150); - } - } - if (emitChange) { - slotUpdateRange(); - } -} - -// virtual -QVariant ClipItem::itemChange(GraphicsItemChange change, const QVariant &value) -{ - if (change == QGraphicsItem::ItemSelectedChange) { - if (value.toBool()) { - setZValue(6); - } else { - setZValue(2); - } - } - CustomTrackScene *scene = nullptr; - if (change == ItemPositionChange) { - scene = projectScene(); - } - if (scene) { - // calculate new position. - // if (parentItem()) return pos(); - if (scene->isZooming) { - // For some reason, mouse wheel on selected itm sometimes triggered - // a position change event corrupting timeline, so discard it - return pos(); - } - if (property("resizingEnd").isValid()) { - return pos(); - } - QPointF newPos = value.toPointF(); - int xpos = scene->getSnapPointForPos((int)newPos.x(), KdenliveSettings::snaptopoints()); - xpos = qMax(xpos, 0); - newPos.setX(xpos); - // Warning: newPos gives a position relative to the click event, so hack to get absolute pos - int newTrack = trackForPos(property("y_absolute").toInt() + newPos.y()); - QList lockedTracks = property("locked_tracks").value>(); - if (lockedTracks.contains(newTrack)) { - // Trying to move to a locked track - return pos(); - } - int maximumTrack = projectScene()->tracksCount(); - newTrack = qMin(newTrack, maximumTrack); - newTrack = qMax(newTrack, 1); - newPos.setY(posForTrack(newTrack)); - // Only one clip is moving - QRectF sceneShape = rect(); - sceneShape.translate(newPos); - QList items; - if (scene->editMode() == TimelineMode::NormalEdit) { - items = scene->items(sceneShape, Qt::IntersectsItemShape); - } - items.removeAll(this); - bool forwardMove = newPos.x() > pos().x(); - if (!items.isEmpty()) { - for (int i = 0; i < items.count(); ++i) { - if (!items.at(i)->isEnabled()) { - continue; - } - if (items.at(i)->type() == type()) { - int offset = 0; - // Collision! - QPointF otherPos = items.at(i)->pos(); - if ((int)otherPos.y() != (int)pos().y()) { - return pos(); - } - if (forwardMove) { - offset = qMax(offset, (int)(newPos.x() - (static_cast(items.at(i))->startPos() - cropDuration()).frames(m_fps))); - } else { - offset = qMax(offset, (int)((static_cast(items.at(i))->endPos().frames(m_fps)) - newPos.x())); - } - if (offset > 0) { - if (forwardMove) { - sceneShape.translate(QPointF(-offset, 0)); - newPos.setX(newPos.x() - offset); - } else { - sceneShape.translate(QPointF(offset, 0)); - newPos.setX(newPos.x() + offset); - } - QList subitems = scene->items(sceneShape, Qt::IntersectsItemShape); - subitems.removeAll(this); - for (int j = 0; j < subitems.count(); ++j) { - if (!subitems.at(j)->isEnabled()) { - continue; - } - if (subitems.at(j)->type() == type()) { - // move was not successful, revert to previous pos - m_info.startPos = GenTime((int)pos().x(), m_fps); - return pos(); - } - } - } - - m_info.track = newTrack; - m_info.startPos = GenTime((int)newPos.x(), m_fps); - - return newPos; - } - } - } - m_info.track = newTrack; - m_info.startPos = GenTime((int)newPos.x(), m_fps); - return newPos; - } - if (change == ItemParentChange) { - QGraphicsItem *parent = value.value(); - if (parent) { - m_paintColor = m_baseColor.lighter(135); - } else { - m_paintColor = m_baseColor; - } - } - return QGraphicsItem::itemChange(change, value); -} - -int ClipItem::effectsCounter() -{ - return effectsCount() + 1; -} - -int ClipItem::effectsCount() -{ - return m_effectList.count(); -} - -int ClipItem::hasEffect(const QString &tag, const QString &id) const -{ - return m_effectList.hasEffect(tag, id); -} - -QStringList ClipItem::effectNames() -{ - return m_effectList.effectNames(); -} - -QDomElement ClipItem::effect(int ix) const -{ - if (ix >= m_effectList.count() || ix < 0) { - return QDomElement(); - } - return m_effectList.at(ix).cloneNode().toElement(); -} - -QDomElement ClipItem::effectAtIndex(int ix) const -{ - if (ix > m_effectList.count() || ix <= 0) { - return QDomElement(); - } - return m_effectList.itemFromIndex(ix).cloneNode().toElement(); -} - -QDomElement ClipItem::getEffectAtIndex(int ix) const -{ - if (ix > m_effectList.count() || ix <= 0) { - return QDomElement(); - } - return m_effectList.itemFromIndex(ix); -} - -void ClipItem::updateEffect(const QDomElement &effect) -{ - m_effectList.updateEffect(effect); - m_effectNames = m_effectList.effectNames().join(QStringLiteral(" / ")); - QString id = effect.attribute(QStringLiteral("id")); - if (id == QLatin1String("fadein") || id == QLatin1String("fadeout") || id == QLatin1String("fade_from_black") || id == QLatin1String("fade_to_black")) { - update(); - } else { - QRectF r = boundingRect(); - r.setHeight(20); - update(r); - } -} - -bool ClipItem::enableEffects(const QList &indexes, bool disable) -{ - return m_effectList.enableEffects(indexes, disable); -} - -bool ClipItem::moveEffect(QDomElement effect, int ix) -{ - if (ix <= 0 || ix > (m_effectList.count()) || effect.isNull()) { - return false; - } - m_effectList.removeAt(effect.attribute(QStringLiteral("kdenlive_ix")).toInt()); - effect.setAttribute(QStringLiteral("kdenlive_ix"), ix); - m_effectList.insert(effect); - m_effectNames = m_effectList.effectNames().join(QStringLiteral(" / ")); - QString id = effect.attribute(QStringLiteral("id")); - if (id == QLatin1String("fadein") || id == QLatin1String("fadeout") || id == QLatin1String("fade_from_black") || id == QLatin1String("fade_to_black")) { - update(); - } else { - QRectF r = boundingRect(); - r.setHeight(20); - update(r); - } - return true; -} - -EffectsParameterList ClipItem::addEffect(QDomElement effect, bool animate) -{ - bool needRepaint = false; - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - int ix; - QDomElement insertedEffect; - if (!effect.hasAttribute(QStringLiteral("kdenlive_ix"))) { - // effect dropped from effect list - ix = effectsCounter(); - } else { - ix = effect.attribute(QStringLiteral("kdenlive_ix")).toInt(); - } - - // Special case, speed effect is a "pseudo" effect, should always appear first and is not movable - if (effect.attribute(QStringLiteral("id")) == QLatin1String("speed")) { - ix = 1; - effect.setAttribute(QStringLiteral("kdenlive_ix"), QStringLiteral("1")); - } - if (!m_effectList.isEmpty() && ix <= m_effectList.count()) { - needRepaint = true; - insertedEffect = m_effectList.insert(effect); - } else { - insertedEffect = m_effectList.append(effect); - } - - // Update index to the real one - effect.setAttribute(QStringLiteral("kdenlive_ix"), insertedEffect.attribute(QStringLiteral("kdenlive_ix"))); - int effectIn; - int effectOut; - - if (effect.attribute(QStringLiteral("tag")) == QLatin1String("affine")) { - // special case: the affine effect needs in / out points - effectIn = effect.attribute(QStringLiteral("in")).toInt(); - effectOut = effect.attribute(QStringLiteral("out")).toInt(); - } else { - effectIn = EffectsList::parameter(effect, QStringLiteral("in")).toInt(); - effectOut = EffectsList::parameter(effect, QStringLiteral("out")).toInt(); - } - - EffectsParameterList parameters; - parameters.addParam(QStringLiteral("tag"), insertedEffect.attribute(QStringLiteral("tag"))); - if (insertedEffect.hasAttribute(QStringLiteral("kdenlive_info"))) { - parameters.addParam(QStringLiteral("kdenlive_info"), insertedEffect.attribute(QStringLiteral("kdenlive_info"))); - } - parameters.addParam(QStringLiteral("kdenlive_ix"), insertedEffect.attribute(QStringLiteral("kdenlive_ix"))); - if (insertedEffect.hasAttribute(QStringLiteral("src"))) { - parameters.addParam(QStringLiteral("src"), insertedEffect.attribute(QStringLiteral("src"))); - } - if (insertedEffect.hasAttribute(QStringLiteral("disable"))) { - parameters.addParam(QStringLiteral("disable"), insertedEffect.attribute(QStringLiteral("disable"))); - } - - QString effectId = insertedEffect.attribute(QStringLiteral("id")); - if (effectId.isEmpty()) { - effectId = insertedEffect.attribute(QStringLiteral("tag")); - } - parameters.addParam(QStringLiteral("id"), effectId); - - QDomNodeList params = insertedEffect.elementsByTagName(QStringLiteral("parameter")); - int fade = 0; - bool needInOutSync = false; - if (effect.hasAttribute(QStringLiteral("sync_in_out")) && effect.attribute(QStringLiteral("sync_in_out")) == QLatin1String("1")) { - needInOutSync = true; - } - - // check if it is a fade effect - if (effectId == QLatin1String("fadein")) { - needRepaint = true; - if (m_effectList.hasEffect(QString(), QStringLiteral("fade_from_black")) == -1) { - fade = effectOut - effectIn; - } /* else { - QDomElement fadein = m_effectList.getEffectByTag(QString(), "fade_from_black"); - if (fadein.attribute("name") == "out") fade += fadein.attribute("value").toInt(); - else if (fadein.attribute("name") == "in") fade -= fadein.attribute("value").toInt(); - }*/ - } else if (effectId == QLatin1String("fade_from_black")) { - needRepaint = true; - if (m_effectList.hasEffect(QString(), QStringLiteral("fadein")) == -1) { - fade = effectOut - effectIn; - } /* else { - QDomElement fadein = m_effectList.getEffectByTag(QString(), "fadein"); - if (fadein.attribute("name") == "out") fade += fadein.attribute("value").toInt(); - else if (fadein.attribute("name") == "in") fade -= fadein.attribute("value").toInt(); - }*/ - } else if (effectId == QLatin1String("fadeout")) { - needRepaint = true; - if (m_effectList.hasEffect(QString(), QStringLiteral("fade_to_black")) == -1) { - fade = effectIn - effectOut; - } /*else { - QDomElement fadeout = m_effectList.getEffectByTag(QString(), "fade_to_black"); - if (fadeout.attribute("name") == "out") fade -= fadeout.attribute("value").toInt(); - else if (fadeout.attribute("name") == "in") fade += fadeout.attribute("value").toInt(); - }*/ - } else if (effectId == QLatin1String("fade_to_black")) { - needRepaint = true; - if (m_effectList.hasEffect(QString(), QStringLiteral("fadeout")) == -1) { - fade = effectIn - effectOut; - } /* else { - QDomElement fadeout = m_effectList.getEffectByTag(QString(), "fadeout"); - if (fadeout.attribute("name") == "out") fade -= fadeout.attribute("value").toInt(); - else if (fadeout.attribute("name") == "in") fade += fadeout.attribute("value").toInt(); - }*/ - } - - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - if (!e.isNull()) { - if (e.attribute(QStringLiteral("type")) == QLatin1String("geometry") && !e.hasAttribute(QStringLiteral("fixed"))) { - // Effects with a geometry parameter need to sync in / out with parent clip - parameters.addParam(e.attribute(QStringLiteral("name")), e.attribute(QStringLiteral("value"))); - if (!e.hasAttribute(QStringLiteral("sync_in_out")) || e.attribute(QStringLiteral("sync_in_out")) == QLatin1String("1")) { - needInOutSync = true; - } - } else if (e.attribute(QStringLiteral("type")) == QLatin1String("animated")) { - parameters.addParam(e.attribute(QStringLiteral("name")), e.attribute(QStringLiteral("value"))); - // Effects with a animated parameter need to sync in / out with parent clip - if (e.attribute(QStringLiteral("sync_in_out")) == QLatin1String("1")) { - needInOutSync = true; - } - } else if (e.attribute(QStringLiteral("type")) == QLatin1String("simplekeyframe")) { - QStringList values = e.attribute(QStringLiteral("keyframes")).split(QLatin1Char(';'), QString::SkipEmptyParts); - double factor = locale.toDouble(e.attribute(QStringLiteral("factor"), QStringLiteral("1"))); - double offset = e.attribute(QStringLiteral("offset"), QStringLiteral("0")).toDouble(); - if (factor != 1 || offset != 0) { - for (int j = 0; j < values.count(); ++j) { - QString pos = values.at(j).section(QLatin1Char('='), 0, 0); - double val = (locale.toDouble(values.at(j).section(QLatin1Char('='), 1, 1)) - offset) / factor; - values[j] = pos + QLatin1Char('=') + locale.toString(val); - } - } - parameters.addParam(e.attribute(QStringLiteral("name")), values.join(QLatin1Char(';'))); - /*parameters.addParam("max", e.attribute("max")); - parameters.addParam("min", e.attribute("min")); - parameters.addParam("factor", );*/ - } else if (e.attribute(QStringLiteral("type")) == QLatin1String("keyframe")) { - parameters.addParam(QStringLiteral("keyframes"), e.attribute(QStringLiteral("keyframes"))); - parameters.addParam(QStringLiteral("max"), e.attribute(QStringLiteral("max"))); - parameters.addParam(QStringLiteral("min"), e.attribute(QStringLiteral("min"))); - parameters.addParam(QStringLiteral("factor"), e.attribute(QStringLiteral("factor"), QStringLiteral("1"))); - parameters.addParam(QStringLiteral("offset"), e.attribute(QStringLiteral("offset"), QStringLiteral("0"))); - parameters.addParam(QStringLiteral("starttag"), e.attribute(QStringLiteral("starttag"), QStringLiteral("start"))); - parameters.addParam(QStringLiteral("endtag"), e.attribute(QStringLiteral("endtag"), QStringLiteral("end"))); - } else if (e.attribute(QStringLiteral("factor"), QStringLiteral("1")) == QLatin1String("1") && - e.attribute(QStringLiteral("offset"), QStringLiteral("0")) == QLatin1String("0")) { - parameters.addParam(e.attribute(QStringLiteral("name")), e.attribute(QStringLiteral("value"))); - } else { - double fact; - if (e.attribute(QStringLiteral("factor")).contains(QLatin1Char('%'))) { - fact = EffectsController::getStringEval(e.attribute(QStringLiteral("factor"))); - } else { - fact = locale.toDouble(e.attribute(QStringLiteral("factor"), QStringLiteral("1"))); - } - double offset = e.attribute(QStringLiteral("offset"), QStringLiteral("0")).toDouble(); - parameters.addParam(e.attribute(QStringLiteral("name")), - locale.toString((locale.toDouble(e.attribute(QStringLiteral("value"))) - offset) / fact)); - } - } - } - if (needInOutSync) { - parameters.addParam(QStringLiteral("in"), QString::number((int)cropStart().frames(m_fps))); - parameters.addParam(QStringLiteral("out"), QString::number((int)(cropStart() + cropDuration()).frames(m_fps) - 1)); - parameters.addParam(QStringLiteral("kdenlive:sync_in_out"), QStringLiteral("1")); - } - m_effectNames = m_effectList.effectNames().join(QStringLiteral(" / ")); - if (fade > 0) { - m_startFade = fade; - } else if (fade < 0) { - m_endFade = -fade; - } - - if (m_selectedEffect == -1) { - setSelectedEffect(1); - } else if (m_selectedEffect == ix - 1) { - setSelectedEffect(m_selectedEffect); - } - - if (needRepaint) { - update(boundingRect()); - } else { - if (animate) { - flashClip(); - } else { - QRectF r = boundingRect(); - // r.setHeight(20); - update(r); - } - } - return parameters; -} - -bool ClipItem::deleteEffect(int ix) -{ - bool needRepaint = false; - bool isVideoEffect = false; - QDomElement effect = m_effectList.itemFromIndex(ix); - if (effect.attribute(QStringLiteral("type")) != QLatin1String("audio")) { - isVideoEffect = true; - } - QString effectId = effect.attribute(QStringLiteral("id")); - if ((effectId == QLatin1String("fadein") && hasEffect(QString(), QStringLiteral("fade_from_black")) == -1) || - (effectId == QLatin1String("fade_from_black") && hasEffect(QString(), QStringLiteral("fadein")) == -1)) { - m_startFade = 0; - needRepaint = true; - } else if ((effectId == QLatin1String("fadeout") && hasEffect(QString(), QStringLiteral("fade_to_black")) == -1) || - (effectId == QLatin1String("fade_to_black") && hasEffect(QString(), QStringLiteral("fadeout")) == -1)) { - m_endFade = 0; - needRepaint = true; - } else if (EffectsList::hasKeyFrames(effect)) { - needRepaint = true; - } - m_effectList.removeAt(ix); - m_effectNames = m_effectList.effectNames().join(QStringLiteral(" / ")); - - if (m_effectList.isEmpty() || m_selectedEffect == ix) { - // Current effect was removed - if (ix > m_effectList.count()) { - setSelectedEffect(m_effectList.count()); - } else { - setSelectedEffect(ix); - } - } - if (needRepaint) { - update(boundingRect()); - } else { - QRectF r = boundingRect(); - // r.setHeight(20); - update(r); - } - if (!m_effectList.isEmpty()) { - flashClip(); - } - return isVideoEffect; -} - -double ClipItem::speed() const -{ - return m_speed; -} - -int ClipItem::strobe() const -{ - return m_strobe; -} - -void ClipItem::setSpeed(const double speed, const int strobe) -{ - m_speed = speed; - if (m_speed <= 0 && m_speed > -1) { - m_speed = -1.0; - } - m_strobe = strobe; - m_info.cropStart = GenTime((int)(m_speedIndependantInfo.cropStart.frames(m_fps) / qAbs(m_speed) + 0.5), m_fps); - m_info.cropDuration = GenTime((int)(m_speedIndependantInfo.cropDuration.frames(m_fps) / qAbs(m_speed) + 0.5), m_fps); - // update(); -} - -GenTime ClipItem::maxDuration() const -{ - return GenTime((int)(m_maxDuration.frames(m_fps) / qAbs(m_speed) + 0.5), m_fps); -} - -GenTime ClipItem::speedIndependantCropStart() const -{ - return m_speedIndependantInfo.cropStart; -} - -GenTime ClipItem::speedIndependantCropDuration() const -{ - return m_speedIndependantInfo.cropDuration; -} - -const ItemInfo ClipItem::speedIndependantInfo() const -{ - return m_speedIndependantInfo; -} - -int ClipItem::nextFreeEffectGroupIndex() const -{ - int freeGroupIndex = 0; - for (int i = 0; i < m_effectList.count(); ++i) { - QDomElement effect = m_effectList.at(i); - EffectInfo effectInfo; - effectInfo.fromString(effect.attribute(QStringLiteral("kdenlive_info"))); - if (effectInfo.groupIndex >= freeGroupIndex) { - freeGroupIndex = effectInfo.groupIndex + 1; - } - } - return freeGroupIndex; -} - -// virtual -void ClipItem::dropEvent(QGraphicsSceneDragDropEvent *event) -{ - if (event->proposedAction() == Qt::CopyAction && (scene() != nullptr) && !scene()->views().isEmpty()) { - if (m_selectionTimer.isActive()) { - m_selectionTimer.stop(); - } - QString effects; - bool transitionDrop = false; - if (event->mimeData()->hasFormat(QStringLiteral("kdenlive/transitionslist"))) { - // Transition drop - effects = QString::fromUtf8(event->mimeData()->data(QStringLiteral("kdenlive/transitionslist"))); - transitionDrop = true; - } else if (event->mimeData()->hasFormat(QStringLiteral("kdenlive/effectslist"))) { - // Effect drop - effects = QString::fromUtf8(event->mimeData()->data(QStringLiteral("kdenlive/effectslist"))); - } else if (event->mimeData()->hasFormat(QStringLiteral("kdenlive/geometry"))) { - if (m_selectionTimer.isActive()) { - m_selectionTimer.stop(); - } - event->acceptProposedAction(); - CustomTrackView *view = static_cast(scene()->views().constFirst()); - if (view) { - QString geometry = QString::fromUtf8(event->mimeData()->data(QStringLiteral("kdenlive/geometry"))); - view->dropClipGeometry(this, geometry); - } - return; - } - event->acceptProposedAction(); - QDomDocument doc; - doc.setContent(effects, true); - QDomElement e = doc.documentElement(); - if (e.tagName() == QLatin1String("effectgroup")) { - // dropped an effect group - QDomNodeList effectlist = e.elementsByTagName(QStringLiteral("effect")); - int freeGroupIndex = nextFreeEffectGroupIndex(); - EffectInfo effectInfo; - for (int i = 0; i < effectlist.count(); ++i) { - QDomElement effect = effectlist.at(i).toElement(); - effectInfo.fromString(effect.attribute(QStringLiteral("kdenlive_info"))); - effectInfo.groupIndex = freeGroupIndex; - effect.setAttribute(QStringLiteral("kdenlive_info"), effectInfo.toString()); - effect.removeAttribute(QStringLiteral("kdenlive_ix")); - } - } else { - // single effect dropped - e.removeAttribute(QStringLiteral("kdenlive_ix")); - } - CustomTrackView *view = static_cast(scene()->views().constFirst()); - if (view) { - if (transitionDrop) { - view->slotDropTransition(this, e, event->scenePos()); - } else { - view->slotDropEffect(this, e, m_info.startPos, track()); - } - } - } else { - return; - } -} - -// virtual -void ClipItem::dragEnterEvent(QGraphicsSceneDragDropEvent *event) -{ - if (isItemLocked()) { - event->setAccepted(false); - } else if (event->mimeData()->hasFormat(QStringLiteral("kdenlive/effectslist")) || - event->mimeData()->hasFormat(QStringLiteral("kdenlive/transitionslist"))) { - event->acceptProposedAction(); - m_selectionTimer.start(); - } else if (event->mimeData()->hasFormat(QStringLiteral("kdenlive/geometry"))) { - m_selectionTimer.start(); - event->acceptProposedAction(); - } else { - event->setAccepted(false); - } -} - -void ClipItem::dragLeaveEvent(QGraphicsSceneDragDropEvent *event) -{ - Q_UNUSED(event) - if (m_selectionTimer.isActive()) { - m_selectionTimer.stop(); - } -} - -void ClipItem::dragMoveEvent(QGraphicsSceneDragDropEvent *event) -{ - QGraphicsItem::dragMoveEvent(event); - if (m_selectionTimer.isActive() && !isSelected()) { - m_selectionTimer.start(); - } -} - -void ClipItem::addTransition(Transition *t) -{ - m_transitionsList.append(t); - // CustomTrackView *view = (CustomTrackView *) scene()->views()[0]; - QDomDocument doc; - QDomElement e = doc.documentElement(); - // if (view) view->slotAddTransition(this, t->toXML() , t->startPos(), track()); -} - -void ClipItem::setState(PlaylistState::ClipState state) -{ - if (state == m_clipState) { - return; - } - if (state == PlaylistState::Disabled) { - m_originalClipState = m_clipState; - } - m_clipState = state; - if (m_clipState == PlaylistState::AudioOnly) { - m_baseColor = QColor(141, 215, 166); - } else { - if (m_clipType == Color) { - QString colour = m_binClip->getProducerProperty(QStringLiteral("colour")); - colour = colour.replace(0, 2, QLatin1Char('#')); - m_baseColor = QColor(colour.left(7)); - } else if (m_clipType == Audio) { - m_baseColor = QColor(141, 215, 166); - } else { - m_baseColor = QColor(141, 166, 215); - } - } - if (parentItem()) { - m_paintColor = m_baseColor.lighter(135); - } else { - m_paintColor = m_baseColor; - } - m_audioThumbCachePic.clear(); -} - -QMap ClipItem::adjustEffectsToDuration(const ItemInfo &oldInfo) -{ - QMap effects; - // qCDebug(KDENLIVE_LOG)<<"Adjusting effect to duration: "< clipEnd) { - if (!effects.contains(i)) { - effects[i] = effect.cloneNode().toElement(); - } - EffectsList::setParameter(effect, QStringLiteral("out"), QString::number(clipEnd)); - } - if (effects.contains(i)) { - setFadeIn(out - in); - } - } else { - if (out != clipEnd) { - effects[i] = effect.cloneNode().toElement(); - int diff = out - clipEnd; - in = qMax(in - diff, (int)cropStart().frames(m_fps)); - out -= diff; - EffectsList::setParameter(effect, QStringLiteral("in"), QString::number(in)); - EffectsList::setParameter(effect, QStringLiteral("out"), QString::number(out)); - } - if (in < cropStart().frames(m_fps)) { - if (!effects.contains(i)) { - effects[i] = effect.cloneNode().toElement(); - } - EffectsList::setParameter(effect, QStringLiteral("in"), QString::number((int)cropStart().frames(m_fps))); - } - if (effects.contains(i)) { - setFadeOut(out - in); - } - } - continue; - } else if (effect.attribute(QStringLiteral("id")) == QLatin1String("freeze") && cropStart() != oldInfo.cropStart) { - effects[i] = effect.cloneNode().toElement(); - int diff = (oldInfo.cropStart - cropStart()).frames(m_fps); - int frame = EffectsList::parameter(effect, QStringLiteral("frame")).toInt(); - EffectsList::setParameter(effect, QStringLiteral("frame"), QString::number(frame - diff)); - continue; - } - - QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter")); - for (int j = 0; j < params.count(); ++j) { - QDomElement param = params.item(j).toElement(); - QString type = param.attribute(QStringLiteral("type")); - if (type == QLatin1String("geometry") && !param.hasAttribute(QStringLiteral("fixed"))) { - if (!effects.contains(i)) { - if (effect.attribute(QStringLiteral("sync_in_out")) == QLatin1String("1")) { - effect.setAttribute(QStringLiteral("in"), cropStart().frames(m_fps)); - effect.setAttribute(QStringLiteral("out"), (cropStart() + cropDuration()).frames(m_fps) - 1); - } - effects[i] = effect.cloneNode().toElement(); - } - // updateGeometryKeyframes(effect, j, oldInfo); - } else if (type == QLatin1String("simplekeyframe") || type == QLatin1String("keyframe")) { - if (!effects.contains(i)) { - effects[i] = effect.cloneNode().toElement(); - } - updateNormalKeyframes(param, oldInfo); - } else if (type.startsWith(QLatin1String("animated"))) { - if (effect.attribute(QStringLiteral("sync_in_out")) == QLatin1String("1")) { - effect.setAttribute(QStringLiteral("in"), cropStart().frames(m_fps)); - effect.setAttribute(QStringLiteral("out"), (cropStart() + cropDuration()).frames(m_fps) - 1); - } - // Check if we have keyframes at in/out points - updateAnimatedKeyframes(i, param, oldInfo); - effects[i] = effect.cloneNode().toElement(); - } else if (type == QLatin1String("roto-spline")) { - if (!effects.contains(i)) { - effects[i] = effect.cloneNode().toElement(); - } - QByteArray value = param.attribute(QStringLiteral("value")).toLatin1(); - /*if (adjustRotoDuration(&value, cropStart().frames(m_fps), (cropStart() + cropDuration()).frames(m_fps) - 1)) { - param.setAttribute(QStringLiteral("value"), QString::fromLatin1(value)); - }*/ - } - } - } - return effects; -} - -bool ClipItem::updateAnimatedKeyframes(int /*ix*/, const QDomElement ¶meter, const ItemInfo &oldInfo) -{ - int in = cropStart().frames(m_fps); - int out = (cropStart() + cropDuration()).frames(m_fps) - 1; - int oldin = oldInfo.cropStart.frames(m_fps); - int oldout = oldin + oldInfo.cropDuration.frames(m_fps) - 1; - return switchKeyframes(parameter, in, oldin, out, oldout); -} - -bool ClipItem::updateNormalKeyframes(QDomElement parameter, const ItemInfo &oldInfo) -{ - int in = cropStart().frames(m_fps); - int out = (cropStart() + cropDuration()).frames(m_fps) - 1; - int oldin = oldInfo.cropStart.frames(m_fps); - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - bool keyFrameUpdated = false; - - const QStringList data = parameter.attribute(QStringLiteral("keyframes")).split(QLatin1Char(';'), QString::SkipEmptyParts); - QMap keyframes; - for (const QString &keyframe : data) { - int keyframepos = keyframe.section(QLatin1Char('='), 0, 0).toInt(); - // if keyframe was at clip start, update it - if (keyframepos == oldin) { - keyframepos = in; - keyFrameUpdated = true; - } - keyframes[keyframepos] = locale.toDouble(keyframe.section(QLatin1Char('='), 1, 1)); - } - - QMap::iterator i = keyframes.end(); - int lastPos = -1; - double lastValue = 0; - qreal relPos; - - /* - * Take care of resize from start - */ - bool startFound = false; - while (i-- != keyframes.begin()) { - if (i.key() < in && !startFound) { - startFound = true; - if (lastPos < 0) { - keyframes[in] = i.value(); - } else { - relPos = (in - i.key()) / (qreal)(lastPos - i.key() + 1); - keyframes[in] = i.value() + (lastValue - i.value()) * relPos; - } - } - lastPos = i.key(); - lastValue = i.value(); - if (startFound) { - i = keyframes.erase(i); - } - } - - /* - * Take care of resize from end - */ - i = keyframes.begin(); - lastPos = -1; - bool endFound = false; - while (i != keyframes.end()) { - if (i.key() > out && !endFound) { - endFound = true; - if (lastPos < 0) { - keyframes[out] = i.value(); - } else { - relPos = (out - lastPos) / (qreal)(i.key() - lastPos + 1); - keyframes[out] = lastValue + (i.value() - lastValue) * relPos; - } - } - lastPos = i.key(); - lastValue = i.value(); - if (endFound) { - i = keyframes.erase(i); - } else { - ++i; - } - } - - if (startFound || endFound || keyFrameUpdated) { - QString newkfr; - QMap::const_iterator k = keyframes.constBegin(); - while (k != keyframes.constEnd()) { - newkfr.append(QString::number(k.key()) + QLatin1Char('=') + QString::number(qRound(k.value())) + QLatin1Char(';')); - ++k; - } - parameter.setAttribute(QStringLiteral("keyframes"), newkfr); - return true; - } - - return false; -} - -void ClipItem::slotRefreshClip() -{ - update(); -} - -bool ClipItem::needsDuplicate() const -{ - return !(m_clipType != AV && m_clipType != Audio && m_clipType != Playlist); -} - -PlaylistState::ClipState ClipItem::clipState() const -{ - return m_clipState; -} - -PlaylistState::ClipState ClipItem::originalState() const -{ - return m_originalClipState; -} - -bool ClipItem::isSplittable() const -{ - return (m_clipState != PlaylistState::VideoOnly && m_binClip->isSplittable()); -} - -void ClipItem::updateState(const QString &id, int aIndex, int vIndex, PlaylistState::ClipState originalState) -{ - bool disabled = false; - if (m_clipType == AV || m_clipType == Playlist) { - disabled = (aIndex == -1 && vIndex == -1); - } else if (m_clipType == Video) { - disabled = (vIndex == -1); - } else if (m_clipType == Audio) { - disabled = (aIndex == -1); - } - if (disabled) { - // We need to find original state from id - m_originalClipState = originalState; - m_clipState = PlaylistState::Disabled; - } else { - m_clipState = PlaylistState::Original; - - if (id.startsWith(QLatin1String("slowmotion"))) { - m_clipState = id.count(QLatin1Char(':')) == 4 ? (PlaylistState::ClipState)id.section(QLatin1Char(':'), -1).toInt() : PlaylistState::Original; - return; - } - if (id.endsWith(QLatin1String("_audio"))) { - m_clipState = PlaylistState::AudioOnly; - } else if (id.endsWith(QLatin1String("_video"))) { - m_clipState = PlaylistState::VideoOnly; - } - } -} - -void ClipItem::slotUpdateThumb(const QImage &img) -{ - m_startPix = QPixmap::fromImage(img); - update(); -} - -void ClipItem::updateKeyframes(const QDomElement &effect) -{ - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - // parse keyframes - QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter")); - QDomElement e = params.item(m_visibleParam).toElement(); - if (e.isNull()) { - return; - } - if (e.attribute(QStringLiteral("intimeline")) != QLatin1String("1")) { - setSelectedEffect(m_selectedEffect); - return; - } - m_keyframeView.loadKeyframes(locale, e, cropStart().frames(m_fps), cropDuration().frames(m_fps)); -} - -bool ClipItem::hasVisibleVideo() const -{ - return (m_clipType != Audio && m_clipState != PlaylistState::AudioOnly && m_clipState != PlaylistState::Disabled); -} diff --git a/src/timeline/clipitem.h b/src/timeline/clipitem.h deleted file mode 100644 index 7d579c125..000000000 --- a/src/timeline/clipitem.h +++ /dev/null @@ -1,260 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2015 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef CLIPITEM_H -#define CLIPITEM_H - -#include "abstractclipitem.h" -#include "effectslist/effectslist.h" -#include "gentime.h" -#include "mltcontroller/effectscontroller.h" - -#include -#include -#include -#include -#include -#include - -class Transition; -class ProjectClip; - -namespace Mlt { -class Producer; -class Profile; -} - -class ClipItem : public AbstractClipItem -{ - Q_OBJECT - -public: - ClipItem(ProjectClip *clip, const ItemInfo &info, double fps, double speed, int strobe, int frame_width, bool generateThumbs = true); - virtual ~ClipItem(); - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *) override; - int type() const override; - void resizeStart(int posx, bool size = true, bool emitChange = true) override; - void resizeEnd(int posx, bool emitChange = true) override; - OperationType operationMode(const QPointF &pos, Qt::KeyboardModifiers modifiers) override; - void updateKeyframes(const QDomElement &effect) override; - static int itemHeight(); - ClipType clipType() const; - const QString &getBinId() const; - const QString getBinHash() const; - ProjectClip *binClip() const; - QString clipName() const; - QDomElement xml() const; - QDomElement itemXml() const; - ClipItem *clone(const ItemInfo &info) const; - const EffectsList effectList() const; - void setFadeOut(int pos); - void setFadeIn(int pos); - void setFades(int in, int out); - - /** @brief Gets the clip's effect names. - * @return The names of the effects in a string list */ - QStringList effectNames(); - - /** @brief Adds an effect to the clip. - * @return The parameters that will be passed to Mlt */ - EffectsParameterList addEffect(QDomElement effect, bool animate = true); - - /** @brief Deletes the effect with id @param ix. - * @return true if deleted effect was video and requires monitor refresh */ - bool deleteEffect(int ix); - - /** @brief Gets the number of effects in this clip. */ - int effectsCount(); - - /** @brief Gets a unique (?) effect id. */ - int effectsCounter(); - - /** @brief Gets a copy of the xml of an effect. - * @param ix The effect's list index (starting from 0) - * @return A copy of the effect's xml */ - QDomElement effect(int ix) const; - - /** @brief Gets a copy of the xml of an effect. - * @param ix The effect's index in effectlist (starting from 1) - * @return A copy of the effect's xml */ - QDomElement effectAtIndex(int ix) const; - - /** @brief Gets the xml of an effect. - * @param ix The effect's index in effectlist (starting from 1) - * @return The effect's xml */ - QDomElement getEffectAtIndex(int ix) const; - - /** @brief Replaces an effect. - * @param ix The effect's index in effectlist - * @param effect The new effect */ - void updateEffect(const QDomElement &effect); - /** @brief Enable / disable a list of effect from their indexes. - * @returns true if some the effects are video effects, requiring a monitor refresh */ - bool enableEffects(const QList &indexes, bool disable); - bool moveEffect(QDomElement effect, int ix); - void flashClip(); - void addTransition(Transition *); - - /** @brief Regenerates audio and video thumbnails. - * @param clearExistingThumbs true = regenerate all thumbs, false = only create missing thumbs. */ - void resetThumbs(bool clearExistingThumbs); - - /** @brief Updates clip properties from base clip. - * @param checkDuration whether or not to check for a valid duration. - * @param resetThumbs whether or not to recreate the image thumbnails. */ - void refreshClip(bool checkDuration, bool resetThumbs); - - /** @brief Gets clip's marker times. - * @return A list of the times. */ - QList snapMarkers(const QList &markers) const; - QList commentedSnapMarkers() const; - - /** @brief Gets the position of the fade in effect. */ - int fadeIn() const; - - /** @brief Gets the position of the fade out effect. */ - int fadeOut() const; - void setSelectedEffect(const int ix); - QDomElement selectedEffect(); - int selectedEffectIndex() const; - void initEffect(const QDomElement &effect, int diff = 0, int offset = 0); - - /** @brief Gets all keyframes. - * @param index Index of the effect - * @return a list of strings of keyframes (one string per param) */ - QStringList keyframes(const int index); - - /** @brief Sets params with keyframes and updates the visible keyframes. - * @param ix Number of the effect - * @param keyframes a list of strings of keyframes (one string per param), which should be used */ - void setKeyframes(const int ix); - void setEffectList(const EffectsList &effectList); - void setSpeed(const double speed, int strobe); - double speed() const; - int strobe() const; - GenTime maxDuration() const override; - GenTime speedIndependantCropStart() const; - GenTime speedIndependantCropDuration() const; - const ItemInfo speedIndependantInfo() const; - int hasEffect(const QString &tag, const QString &id) const; - - /** @brief Makes sure all keyframes are in the clip's cropped duration. - * @param cutPos the frame number where the new clip starts - * @return Whether or not changes were made */ - bool checkKeyFrames(int width, int height, int previousDuration, int cutPos = -1); - QPixmap startThumb() const; - QPixmap endThumb() const; - void setState(PlaylistState::ClipState state); - void updateState(const QString &id, int aIndex, int vIndex, PlaylistState::ClipState originalState); - bool updateAnimatedKeyframes(int ix, const QDomElement ¶meter, const ItemInfo &oldInfo); - bool updateNormalKeyframes(QDomElement parameter, const ItemInfo &oldInfo); - - /** @brief Adjusts effects after a clip duration change. */ - QMap adjustEffectsToDuration(const ItemInfo &oldInfo); - - /** Returns the necessary (audio, video, general) producer. - * @param track Track of the requested producer - * @param trackSpecific (default = true) Whether to return general producer for a specific track. - * @return Fitting producer - * Which producer is returned depends on the type of this clip (audioonly, videoonly, normal) */ - // Mlt::Producer *getProducer(int track, bool trackSpecific = true); - void resetFrameWidth(int width); - /** @brief Clip is about to be deleted, block thumbs. */ - void stopThumbs(); - - /** @brief Get a free index value for effect group. */ - int nextFreeEffectGroupIndex() const; - - /** @brief Returns true of this clip needs a duplicate (MLT requires duplicate for clips with audio or we get clicks. */ - bool needsDuplicate() const; - - /** @brief Returns true if this has audio. */ - bool isSplittable() const; - - /** @brief Returns some info useful for recreating this clip. */ - PlaylistState::ClipState clipState() const; - PlaylistState::ClipState originalState() const; - /** @brief Returns true if this clip is currently displaying video. */ - bool hasVisibleVideo() const; - -protected: - void dragEnterEvent(QGraphicsSceneDragDropEvent *event) override; - void dragLeaveEvent(QGraphicsSceneDragDropEvent *event) override; - void dragMoveEvent(QGraphicsSceneDragDropEvent *event) override; - void dropEvent(QGraphicsSceneDragDropEvent *event) override; - // virtual void hoverEnterEvent(QGraphicsSceneHoverEvent *); - // virtual void hoverLeaveEvent(QGraphicsSceneHoverEvent *); - QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; - -private: - ProjectClip *m_binClip; - ItemInfo m_speedIndependantInfo; - ClipType m_clipType; - QString m_effectNames; - int m_startFade; - int m_endFade; - PlaylistState::ClipState m_clipState; - PlaylistState::ClipState m_originalClipState; - QColor m_baseColor; - QColor m_paintColor; - - QPixmap m_startPix; - QPixmap m_endPix; - - bool m_hasThumbs; - QTimer m_startThumbTimer; - QTimer m_endThumbTimer; - - QTimeLine *m_timeLine; - bool m_startThumbRequested; - bool m_endThumbRequested; - // bool m_hover; - double m_speed; - int m_strobe; - - EffectsList m_effectList; - QList m_transitionsList; - QMap m_audioThumbCachePic; - bool m_audioThumbReady; - double m_framePixelWidth; - -private slots: - void slotGetStartThumb(); - void slotGetEndThumb(); - void slotGotAudioData(); - void animate(qreal value); - void slotSetStartThumb(const QImage &img); - void slotSetEndThumb(const QImage &img); - void slotThumbReady(int frame, const QImage &img); - /** @brief For fixed thumbnail clip (image / titles), update thumb to reflect bin thumbnail. */ - void slotUpdateThumb(const QImage &); - /** @brief Something changed a detail in clip (thumbs, markers,...), repaint. */ - void slotRefreshClip(); - -public slots: - void slotFetchThumbs(); - void slotSetStartThumb(const QPixmap &pix); - void slotSetEndThumb(const QPixmap &pix); - void slotUpdateRange(); - -signals: - void updateRange(); -}; - -#endif diff --git a/src/timeline/customruler.cpp b/src/timeline/customruler.cpp deleted file mode 100644 index ed62208cd..000000000 --- a/src/timeline/customruler.cpp +++ /dev/null @@ -1,690 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "customruler.h" - -#include "kdenlivesettings.h" - -#include -#include -#include -#include - -#include -#include -#include -#include - -// Height of the ruler display -static int MAX_HEIGHT; -// Height of the ruler display + timeline preview ruler -static int FULL_HEIGHT; -// Width of a frame in pixels -static int FRAME_SIZE; -// Height of the timecode text -static int LABEL_SIZE; -// Height of the timeline preview -static int PREVIEW_SIZE; -// Width of a letter, used for cursor width -static int FONT_WIDTH; - -static int MIDDLE_MARK_X; -static int LITTLE_MARK_X; - -static int littleMarkDistance; -static int mediumMarkDistance; -static int bigMarkDistance; - -#define SEEK_INACTIVE (-1) - -#include "definitions.h" - -const int CustomRuler::comboScale[] = {1, 2, 5, 10, 25, 50, 125, 250, 500, 750, 1500, 3000, 6000, 12000}; - -CustomRuler::CustomRuler(const Timecode &tc, const QList &rulerActions, CustomTrackView *parent) - : QWidget(parent) - , m_timecode(tc) - , m_view(parent) - , m_duration(0) - , m_offset(0) - , m_hidePreview(true) - , m_headPosition(SEEK_INACTIVE) - , m_clickedGuide(-1) - , m_rate(-1) - , m_mouseMove(NO_MOVE) -{ - setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); - QFontMetricsF fontMetrics(font()); - // Define size variables - LABEL_SIZE = fontMetrics.ascent(); - FONT_WIDTH = fontMetrics.averageCharWidth(); - PREVIEW_SIZE = LABEL_SIZE / 3; - setFixedHeight(LABEL_SIZE * 2); - MAX_HEIGHT = height() - 1; - FULL_HEIGHT = MAX_HEIGHT; - int mark_length = MAX_HEIGHT - LABEL_SIZE - 1; - MIDDLE_MARK_X = LABEL_SIZE + mark_length / 3; - LITTLE_MARK_X = LABEL_SIZE + mark_length / 2; - updateFrameSize(); - m_scale = 3; - m_zoneStart = 0; - m_zoneEnd = 100; - m_contextMenu = new QMenu(this); - m_contextMenu->addActions(rulerActions); - QAction *addGuide = m_contextMenu->addAction(QIcon::fromTheme(QStringLiteral("list-add")), i18n("Add Guide")); - connect(addGuide, &QAction::triggered, m_view, &CustomTrackView::slotAddGuide); - m_editGuide = m_contextMenu->addAction(QIcon::fromTheme(QStringLiteral("document-properties")), i18n("Edit Guide")); - connect(m_editGuide, &QAction::triggered, this, &CustomRuler::slotEditGuide); - m_deleteGuide = m_contextMenu->addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete Guide")); - connect(m_deleteGuide, &QAction::triggered, this, &CustomRuler::slotDeleteGuide); - QAction *delAllGuides = m_contextMenu->addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete All Guides")); - connect(delAllGuides, &QAction::triggered, m_view, &CustomTrackView::slotDeleteAllGuides); - m_goMenu = m_contextMenu->addMenu(i18n("Go To")); - connect(m_goMenu, &QMenu::triggered, this, &CustomRuler::slotGoToGuide); - setMouseTracking(true); - m_zoneBG = palette().color(QPalette::Highlight); - m_zoneBG.setAlpha(KdenliveSettings::useTimelineZoneToEdit() ? 180 : 60); -} - -void CustomRuler::updateProjectFps(const Timecode &t) -{ - m_timecode = t; - mediumMarkDistance = FRAME_SIZE * m_timecode.fps(); - bigMarkDistance = FRAME_SIZE * m_timecode.fps() * 60; - setPixelPerMark(m_rate); - update(); -} - -void CustomRuler::updateFrameSize() -{ - FRAME_SIZE = m_view->getFrameWidth(); - littleMarkDistance = FRAME_SIZE; - mediumMarkDistance = FRAME_SIZE * m_timecode.fps(); - bigMarkDistance = FRAME_SIZE * m_timecode.fps() * 60; - updateProjectFps(m_timecode); - if (m_rate > 0) { - setPixelPerMark(m_rate); - } -} - -void CustomRuler::slotEditGuide() -{ - m_view->slotEditGuide(m_clickedGuide); -} - -void CustomRuler::slotDeleteGuide() -{ - m_view->slotDeleteGuide(m_clickedGuide); -} - -void CustomRuler::slotGoToGuide(QAction *act) -{ - m_view->seekCursorPos(act->data().toInt()); - m_view->initCursorPos(act->data().toInt()); -} - -void CustomRuler::setZone(const QPoint &p) -{ - m_zoneStart = p.x(); - m_zoneEnd = p.y(); - update(); -} - -void CustomRuler::mouseReleaseEvent(QMouseEvent *event) -{ - event->setAccepted(true); - if (m_moveCursor == RULER_START || m_moveCursor == RULER_END || m_moveCursor == RULER_MIDDLE) { - emit zoneMoved(m_zoneStart, m_zoneEnd); - m_view->setDocumentModified(); - } - m_mouseMove = NO_MOVE; -} - -// virtual -void CustomRuler::mousePressEvent(QMouseEvent *event) -{ - event->setAccepted(true); - int pos = (int)((event->x() + offset())); - if (event->button() == Qt::RightButton) { - m_clickedGuide = m_view->hasGuide(pos, false); - m_editGuide->setEnabled(m_clickedGuide > 0); - m_deleteGuide->setEnabled(m_clickedGuide > 0); - m_view->buildGuidesMenu(m_goMenu); - m_contextMenu->exec(event->globalPos()); - return; - } - setFocus(Qt::MouseFocusReason); - m_view->activateMonitor(); - m_moveCursor = RULER_CURSOR; - if (event->y() > LABEL_SIZE) { - if (qAbs(pos - m_zoneStart * m_factor) < 4) { - m_moveCursor = RULER_START; - } else if (qAbs(pos - (m_zoneStart + (m_zoneEnd - m_zoneStart) / 2.0) * m_factor) < 4) { - m_moveCursor = RULER_MIDDLE; - } else if (qAbs(pos - (m_zoneEnd + 1) * m_factor) < 4) { - m_moveCursor = RULER_END; - } - m_view->updateSnapPoints(nullptr); - } - if (m_moveCursor == RULER_CURSOR) { - m_view->seekCursorPos((int)pos / m_factor); - m_clickPoint = event->pos(); - m_startRate = m_rate; - } -} - -// virtual -void CustomRuler::mouseMoveEvent(QMouseEvent *event) -{ - event->setAccepted(true); - int mappedXPos = (int)((event->x() + offset()) / m_factor); - emit mousePosition(mappedXPos); - if (event->buttons() == Qt::LeftButton) { - int pos; - if (m_moveCursor == RULER_START || m_moveCursor == RULER_END) { - pos = m_view->getSnapPointForPos(mappedXPos); - } else { - pos = mappedXPos; - } - int zoneStart = m_zoneStart; - int zoneEnd = m_zoneEnd; - if (pos < 0) { - pos = 0; - } - if (m_moveCursor == RULER_CURSOR) { - QPoint diff = event->pos() - m_clickPoint; - if (m_mouseMove == NO_MOVE) { - if (qAbs(diff.x()) >= QApplication::startDragDistance()) { - m_mouseMove = HORIZONTAL_MOVE; - } else if (KdenliveSettings::verticalzoom() && qAbs(diff.y()) >= QApplication::startDragDistance()) { - m_mouseMove = VERTICAL_MOVE; - } else { - return; - } - } - if (m_mouseMove == HORIZONTAL_MOVE) { - if (pos != m_headPosition && pos != m_view->cursorPos()) { - int x = m_headPosition == SEEK_INACTIVE ? pos : m_headPosition; - m_headPosition = pos; - int min = qMin(x, m_headPosition); - int max = qMax(x, m_headPosition); - update(min * m_factor - offset() - 3, LABEL_SIZE, (max - min) * m_factor + 6, FULL_HEIGHT - LABEL_SIZE); - emit seekCursorPos(pos); - m_view->slotCheckPositionScrolling(); - } - } else { - int verticalDiff = m_startRate - (diff.y()) / 7; - if (verticalDiff != m_rate) { - emit adjustZoom(verticalDiff); - } - } - return; - } - if (m_moveCursor == RULER_START) { - m_zoneStart = qMin(pos, m_zoneEnd); - } else if (m_moveCursor == RULER_END) { - m_zoneEnd = qMax(pos, m_zoneStart); - } else if (m_moveCursor == RULER_MIDDLE) { - int move = pos - (m_zoneStart + (m_zoneEnd - m_zoneStart) / 2); - if (move + m_zoneStart < 0) { - move = -m_zoneStart; - } - m_zoneStart += move; - m_zoneEnd += move; - } - int min = qMin(m_zoneStart, zoneStart); - int max = qMax(m_zoneEnd, zoneEnd); - update(min * m_factor - m_offset - 2, LABEL_SIZE, (max - min + 1) * m_factor + 4, FULL_HEIGHT - LABEL_SIZE); - - } else { - int pos = (int)((event->x() + m_offset)); - if (event->y() <= LABEL_SIZE) { - setCursor(Qt::ArrowCursor); - } else if (qAbs(pos - m_zoneStart * m_factor) < 4) { - setCursor(QCursor(Qt::SizeHorCursor)); - if (KdenliveSettings::frametimecode()) { - setToolTip(i18n("Zone start: %1", m_zoneStart)); - } else { - setToolTip(i18n("Zone start: %1", m_timecode.getTimecodeFromFrames(m_zoneStart))); - } - } else if (qAbs(pos - (m_zoneEnd + 1) * m_factor) < 4) { - setCursor(QCursor(Qt::SizeHorCursor)); - if (KdenliveSettings::frametimecode()) { - setToolTip(i18n("Zone end: %1", m_zoneEnd)); - } else { - setToolTip(i18n("Zone end: %1", m_timecode.getTimecodeFromFrames(m_zoneEnd))); - } - } else if (qAbs(pos - (m_zoneStart + (m_zoneEnd - m_zoneStart) / 2.0) * m_factor) < 4) { - setCursor(Qt::SizeHorCursor); - if (KdenliveSettings::frametimecode()) { - setToolTip(i18n("Zone duration: %1", m_zoneEnd - m_zoneStart)); - } else { - setToolTip(i18n("Zone duration: %1", m_timecode.getTimecodeFromFrames(m_zoneEnd - m_zoneStart))); - } - } else { - setCursor(Qt::ArrowCursor); - if (KdenliveSettings::frametimecode()) { - setToolTip(i18n("Position: %1", (int)(pos / m_factor))); - } else { - setToolTip(i18n("Position: %1", m_timecode.getTimecodeFromFrames(pos / m_factor))); - } - } - } -} - -// virtual -void CustomRuler::wheelEvent(QWheelEvent *e) -{ - int delta = 1; - m_view->activateMonitor(); - if (e->modifiers() == Qt::ControlModifier) { - delta = m_timecode.fps(); - } - if (e->delta() < 0) { - delta = 0 - delta; - } - m_view->moveCursorPos(delta); -} - -int CustomRuler::inPoint() const -{ - return m_zoneStart; -} - -int CustomRuler::outPoint() const -{ - return m_zoneEnd; -} - -void CustomRuler::slotMoveRuler(int newPos) -{ - if (m_offset != newPos) { - m_offset = newPos; - update(); - } -} - -int CustomRuler::offset() const -{ - return m_offset; -} - -void CustomRuler::slotCursorMoved(int oldpos, int newpos) -{ - int min = qMin(oldpos, newpos); - int max = qMax(oldpos, newpos); - m_headPosition = newpos; - update(min * m_factor - m_offset - FONT_WIDTH, LABEL_SIZE, (max - min) * m_factor + FONT_WIDTH * 2 + 2, FULL_HEIGHT - LABEL_SIZE); -} - -void CustomRuler::updateRuler(int pos) -{ - int x = m_headPosition; - m_headPosition = pos; - if (x == SEEK_INACTIVE) { - x = pos; - } - int min = qMin(x, m_headPosition); - int max = qMax(x, m_headPosition); - update(min * m_factor - offset() - 3, LABEL_SIZE, (max - min) * m_factor + 6, FULL_HEIGHT - LABEL_SIZE); -} - -void CustomRuler::setPixelPerMark(int rate, bool force) -{ - if (rate < 0 || (rate == m_rate && !force)) { - return; - } - int scale = comboScale[rate]; - m_rate = rate; - m_factor = 1.0 / (double)scale * FRAME_SIZE; - m_scale = 1.0 / (double)scale; - double fend = m_scale * littleMarkDistance; - int textFactor = 1; - int timeLabelSize = QWidget::fontMetrics().boundingRect(QStringLiteral("00:00:00:000")).width(); - if (timeLabelSize > littleMarkDistance) { - textFactor = timeLabelSize / littleMarkDistance + 1; - } - if (rate > 8) { - mediumMarkDistance = (double)FRAME_SIZE * m_timecode.fps() * 60; - bigMarkDistance = (double)FRAME_SIZE * m_timecode.fps() * 300; - } else if (rate > 6) { - mediumMarkDistance = (double)FRAME_SIZE * m_timecode.fps() * 10; - bigMarkDistance = (double)FRAME_SIZE * m_timecode.fps() * 30; - } else if (rate > 3) { - mediumMarkDistance = (double)FRAME_SIZE * m_timecode.fps(); - bigMarkDistance = (double)FRAME_SIZE * m_timecode.fps() * 5; - } else { - mediumMarkDistance = (double)FRAME_SIZE * m_timecode.fps(); - bigMarkDistance = (double)FRAME_SIZE * m_timecode.fps() * 60; - } - - m_textSpacing = fend * textFactor; - - if (m_textSpacing < timeLabelSize) { - int roundedFps = (int)(m_timecode.fps() + 0.5); - int factor = timeLabelSize / m_textSpacing; - if (factor < 2) { - m_textSpacing *= 2; - } else if (factor < 5) { - m_textSpacing *= 5; - } else if (factor < 10) { - m_textSpacing *= 10; - } else if (factor < roundedFps) { - m_textSpacing *= roundedFps; - } else if (factor < 2 * roundedFps) { - m_textSpacing *= 2 * roundedFps; - } else if (factor < 5 * roundedFps) { - m_textSpacing *= 5 * roundedFps; - } else if (factor < 10 * roundedFps) { - m_textSpacing *= 10 * roundedFps; - } else if (factor < 20 * roundedFps) { - m_textSpacing *= 20 * roundedFps; - } else if (factor < 60 * roundedFps) { - m_textSpacing *= 60 * roundedFps; - } else if (factor < 120 * roundedFps) { - m_textSpacing *= 120 * roundedFps; - } else if (factor < 150 * roundedFps) { - m_textSpacing *= 150 * roundedFps; - } else if (factor < 300 * roundedFps) { - m_textSpacing *= 300 * roundedFps; - } else { - factor /= (300 * roundedFps); - m_textSpacing *= (factor + 1) * (300 * roundedFps); - } - } - update(); -} - -void CustomRuler::setDuration(int d) -{ - int oldduration = m_duration; - m_duration = d; - update(qMin(oldduration, m_duration) * m_factor - 1 - offset(), 0, qAbs(oldduration - m_duration) * m_factor + 2, FULL_HEIGHT); -} - -// virtual -void CustomRuler::paintEvent(QPaintEvent *e) -{ - QStylePainter p(this); - const QRect &paintRect = e->rect(); - p.setClipRect(paintRect); - p.fillRect(paintRect, palette().midlight().color()); - - // Draw zone background - const int zoneStart = (int)(m_zoneStart * m_factor); - const int zoneEnd = (int)((m_zoneEnd + 1) * m_factor); - int zoneHeight = LABEL_SIZE * 0.8; - p.fillRect(zoneStart - m_offset, MAX_HEIGHT - zoneHeight + 1, zoneEnd - zoneStart, zoneHeight - 1, m_zoneBG); - - double f, fend; - const int offsetmax = ((paintRect.right() + m_offset) / FRAME_SIZE + 1) * FRAME_SIZE; - int offsetmin; - - p.setPen(palette().text().color()); - // draw time labels - if (paintRect.y() < LABEL_SIZE) { - offsetmin = (paintRect.left() + m_offset) / m_textSpacing; - offsetmin = offsetmin * m_textSpacing; - for (f = offsetmin; f < offsetmax; f += m_textSpacing) { - QString lab; - if (KdenliveSettings::frametimecode()) { - lab = QString::number((int)(f / m_factor + 0.5)); - } else { - lab = m_timecode.getTimecodeFromFrames((int)(f / m_factor + 0.5)); - } - p.drawText(f - m_offset + 2, LABEL_SIZE, lab); - } - } - p.setPen(palette().dark().color()); - offsetmin = (paintRect.left() + m_offset) / littleMarkDistance; - offsetmin = offsetmin * littleMarkDistance; - // draw the little marks - fend = m_scale * littleMarkDistance; - if (fend > 5) { - QLineF l(offsetmin - m_offset, LITTLE_MARK_X, offsetmin - m_offset, MAX_HEIGHT); - for (f = offsetmin; f < offsetmax; f += fend) { - l.translate(fend, 0); - p.drawLine(l); - } - } - - offsetmin = (paintRect.left() + m_offset) / mediumMarkDistance; - offsetmin = offsetmin * mediumMarkDistance; - // draw medium marks - fend = m_scale * mediumMarkDistance; - if (fend > 5) { - QLineF l(offsetmin - m_offset - fend, MIDDLE_MARK_X, offsetmin - m_offset - fend, MAX_HEIGHT); - for (f = offsetmin - fend; f < offsetmax + fend; f += fend) { - l.translate(fend, 0); - p.drawLine(l); - } - } - - offsetmin = (paintRect.left() + m_offset) / bigMarkDistance; - offsetmin = offsetmin * bigMarkDistance; - // draw big marks - fend = m_scale * bigMarkDistance; - if (fend > 5) { - QLineF l(offsetmin - m_offset, LABEL_SIZE, offsetmin - m_offset, MAX_HEIGHT); - for (f = offsetmin; f < offsetmax; f += fend) { - l.translate(fend, 0); - p.drawLine(l); - } - } - // draw zone handles - if (zoneStart > 0) { - QPolygon pa(4); - pa.setPoints(4, zoneStart - m_offset + FONT_WIDTH / 2, MAX_HEIGHT - zoneHeight, zoneStart - m_offset, MAX_HEIGHT - zoneHeight, zoneStart - m_offset, - MAX_HEIGHT, zoneStart - m_offset + FONT_WIDTH / 2, MAX_HEIGHT); - p.drawPolyline(pa); - } - - if (zoneEnd > 0) { - QColor center(Qt::white); - center.setAlpha(150); - QRect rec(zoneStart - m_offset + (zoneEnd - zoneStart - zoneHeight) / 2 + 2, MAX_HEIGHT - zoneHeight + 2, zoneHeight - 4, zoneHeight - 4); - p.fillRect(rec, center); - p.drawRect(rec); - - QPolygon pa(4); - pa.setPoints(4, zoneEnd - m_offset - FONT_WIDTH / 2, MAX_HEIGHT - zoneHeight, zoneEnd - m_offset, MAX_HEIGHT - zoneHeight, zoneEnd - m_offset, - MAX_HEIGHT, zoneEnd - m_offset - FONT_WIDTH / 2, MAX_HEIGHT); - p.drawPolyline(pa); - } - - // draw Rendering preview zones - if (!m_hidePreview) { - p.setPen(palette().dark().color()); - p.drawLine(paintRect.left(), MAX_HEIGHT, paintRect.right(), MAX_HEIGHT); - p.fillRect(paintRect.left(), MAX_HEIGHT + 1, paintRect.width(), PREVIEW_SIZE - 1, palette().mid().color()); - QColor preview(Qt::green); - preview.setAlpha(120); - double chunkWidth = KdenliveSettings::timelinechunks() * m_factor; - for (int frame : m_renderingPreviews) { - double xPos = frame * m_factor - m_offset; - if (xPos + chunkWidth < paintRect.x() || xPos > paintRect.right()) { - continue; - } - QRectF rec(xPos, MAX_HEIGHT + 1, chunkWidth, PREVIEW_SIZE - 1); - p.fillRect(rec, preview); - } - preview = QColor(200, 0, 0); - preview.setAlpha(120); - for (int frame : m_dirtyRenderingPreviews) { - double xPos = frame * m_factor - m_offset; - if (xPos + chunkWidth < paintRect.x() || xPos > paintRect.right()) { - continue; - } - QRectF rec(xPos, MAX_HEIGHT + 1, chunkWidth, PREVIEW_SIZE - 1); - p.fillRect(rec, preview); - } - preview = palette().dark().color(); - preview.setAlpha(70); - p.fillRect(paintRect.left(), MAX_HEIGHT + 1, paintRect.width(), 2, preview); - p.drawLine(paintRect.left(), MAX_HEIGHT + PREVIEW_SIZE, paintRect.right(), MAX_HEIGHT + PREVIEW_SIZE); - } - - if (m_headPosition == m_view->cursorPos()) { - m_headPosition = SEEK_INACTIVE; - } - if (m_headPosition != SEEK_INACTIVE) { - p.fillRect(m_headPosition * m_factor - m_offset - 1, LABEL_SIZE + 1, 3, FULL_HEIGHT - LABEL_SIZE - 1, palette().linkVisited()); - } - - // draw pointer - const int value = m_view->cursorPos() * m_factor - m_offset; - QPolygon pa(3); - pa.setPoints(3, value - FONT_WIDTH, FULL_HEIGHT - FONT_WIDTH, value + FONT_WIDTH, FULL_HEIGHT - FONT_WIDTH, value, FULL_HEIGHT); - p.setBrush(palette().brush(QPalette::Text)); - p.setPen(Qt::NoPen); - p.drawPolygon(pa); -} - -void CustomRuler::activateZone() -{ - m_zoneBG.setAlpha(KdenliveSettings::useTimelineZoneToEdit() ? 180 : 60); - update(); -} - -bool CustomRuler::isUnderPreview(int start, int end) -{ - QList allPreviews; - allPreviews << m_renderingPreviews << m_dirtyRenderingPreviews; - qSort(allPreviews); - for (int ix : allPreviews) { - if (ix >= start && ix <= end) { - return true; - } - } - return false; -} - -bool CustomRuler::updatePreview(int frame, bool rendered, bool refresh) -{ - bool result = false; - if (rendered) { - m_renderingPreviews << frame; - m_dirtyRenderingPreviews.removeAll(frame); - } else { - if (m_renderingPreviews.removeAll(frame) > 0) { - m_dirtyRenderingPreviews << frame; - result = true; - } - } - std::sort(m_renderingPreviews.begin(), m_renderingPreviews.end()); - std::sort(m_dirtyRenderingPreviews.begin(), m_dirtyRenderingPreviews.end()); - if (refresh && !m_hidePreview) { - update(frame * m_factor - offset(), MAX_HEIGHT, KdenliveSettings::timelinechunks() * m_factor + 1, PREVIEW_SIZE); - } - return result; -} - -void CustomRuler::hidePreview(bool hide) -{ - m_hidePreview = hide; - if (hide) { - emit resizeRuler(MAX_HEIGHT + 1); - setFixedHeight(MAX_HEIGHT + 1); - // MAX_HEIGHT = height(); - } else { - emit resizeRuler(MAX_HEIGHT + PREVIEW_SIZE + 1); - setFixedHeight(MAX_HEIGHT + PREVIEW_SIZE + 1); - // MAX_HEIGHT = height() - LABEL_SIZE / 3; - } - update(); -} - -void CustomRuler::updatePreviewDisplay(int start, int end) -{ - if (!m_hidePreview) { - update(start * m_factor - offset(), MAX_HEIGHT, (end - start) * KdenliveSettings::timelinechunks() * m_factor + 1, PREVIEW_SIZE); - } -} - -const QPair CustomRuler::previewChunks() const -{ - QStringList clean; - QStringList dirty; - for (int frame : m_renderingPreviews) { - clean << QString::number(frame); - } - for (int frame : m_dirtyRenderingPreviews) { - dirty << QString::number(frame); - } - QPair resultChunks; - resultChunks.first = clean; - resultChunks.second = dirty; - return resultChunks; -} - -const QList CustomRuler::getProcessedChunks() const -{ - return m_renderingPreviews; -} - -const QList CustomRuler::getDirtyChunks() const -{ - return m_dirtyRenderingPreviews; -} - -bool CustomRuler::hasPreviewRange() const -{ - return (!m_dirtyRenderingPreviews.isEmpty() || !m_renderingPreviews.isEmpty()); -} - -void CustomRuler::clearChunks() -{ - m_renderingPreviews.clear(); - m_dirtyRenderingPreviews.clear(); - update(); -} - -QList CustomRuler::addChunks(QList chunks, bool add) -{ - qSort(chunks); - QList toProcess; - if (add) { - for (int frame : chunks) { - if (m_renderingPreviews.contains(frame)) { - // already rendered, ignore - continue; - } - if (m_dirtyRenderingPreviews.contains(frame)) { - continue; - } - m_dirtyRenderingPreviews << frame; - // This is a new dirty chunk - toProcess << frame; - } - } else { - for (int frame : chunks) { - if (m_renderingPreviews.removeAll(frame) > 0) { - // A preview file existed for this chunk, ask deletion - toProcess << frame; - } - m_dirtyRenderingPreviews.removeAll(frame); - } - } - std::sort(m_renderingPreviews.begin(), m_renderingPreviews.end()); - std::sort(m_dirtyRenderingPreviews.begin(), m_dirtyRenderingPreviews.end()); - if (!m_hidePreview) { - update(chunks.constFirst() * m_factor - offset(), MAX_HEIGHT, (chunks.last() - chunks.constFirst()) * KdenliveSettings::timelinechunks() * m_factor + 1, PREVIEW_SIZE); - } - return toProcess; -} diff --git a/src/timeline/customruler.h b/src/timeline/customruler.h deleted file mode 100644 index a0d6d7d95..000000000 --- a/src/timeline/customruler.h +++ /dev/null @@ -1,123 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -/** - * @class CustomRuler - * @author Jean-Baptiste Mardelle - * @brief Manages the timeline ruler. - */ - -#ifndef CUSTOMRULER_H -#define CUSTOMRULER_H - -#include -#include - -#include "timecode.h" -#include "timeline/customtrackview.h" - -enum RULER_MOVE { RULER_CURSOR = 0, RULER_START = 1, RULER_MIDDLE = 2, RULER_END = 3 }; -enum MOUSE_MOVE { NO_MOVE = 0, HORIZONTAL_MOVE = 1, VERTICAL_MOVE = 2 }; - -class CustomRuler : public QWidget -{ - Q_OBJECT - -public: - CustomRuler(const Timecode &tc, const QList &rulerActions, CustomTrackView *parent); - void setPixelPerMark(int rate, bool force = false); - static const int comboScale[]; - int outPoint() const; - int inPoint() const; - void setDuration(int d); - void setZone(const QPoint &p); - int offset() const; - void updateProjectFps(const Timecode &t); - void updateFrameSize(); - void activateZone(); - bool updatePreview(int frame, bool rendered = true, bool refresh = false); - /** @brief Returns a list of rendered timeline preview chunks */ - const QPair previewChunks() const; - /** @brief Returns a list of clean timeline preview chunks (that have been created) */ - const QList getProcessedChunks() const; - /** @brief Returns a list of dirty timeline preview chunks (that need to be generated) */ - const QList getDirtyChunks() const; - void clearChunks(); - QList addChunks(QList chunks, bool add); - /** @brief Returns true if a timeline preview zone has already be defined */ - bool hasPreviewRange() const; - /** @brief Refresh timeline preview range */ - void updatePreviewDisplay(int start, int end); - bool isUnderPreview(int start, int end); - void hidePreview(bool hide); - -protected: - void paintEvent(QPaintEvent * /*e*/) override; - void wheelEvent(QWheelEvent *e) override; - void mousePressEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; - void mouseMoveEvent(QMouseEvent *event) override; - -private: - Timecode m_timecode; - CustomTrackView *m_view; - int m_zoneStart; - int m_zoneEnd; - int m_duration; - double m_textSpacing; - double m_factor; - double m_scale; - int m_offset; - bool m_hidePreview; - /** @brief the position of the seek point */ - int m_headPosition; - QColor m_zoneBG; - RULER_MOVE m_moveCursor; - QMenu *m_contextMenu; - QAction *m_editGuide; - QAction *m_deleteGuide; - int m_clickedGuide; - /** Used for zooming through vertical move */ - QPoint m_clickPoint; - int m_rate; - int m_startRate; - MOUSE_MOVE m_mouseMove; - QMenu *m_goMenu; - QList m_renderingPreviews; - QList m_dirtyRenderingPreviews; - -public slots: - void slotMoveRuler(int newPos); - void slotCursorMoved(int oldpos, int newpos); - void updateRuler(int pos); - -private slots: - void slotEditGuide(); - void slotDeleteGuide(); - void slotGoToGuide(QAction *act); - -signals: - void zoneMoved(int, int); - void adjustZoom(int); - void mousePosition(int); - void seekCursorPos(int); - void resizeRuler(int); -}; - -#endif diff --git a/src/timeline/customtrackscene.cpp b/src/timeline/customtrackscene.cpp deleted file mode 100644 index 736c3210d..000000000 --- a/src/timeline/customtrackscene.cpp +++ /dev/null @@ -1,110 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "customtrackscene.h" -#include "timeline.h" - -CustomTrackScene::CustomTrackScene(Timeline *timeline, QObject *parent) - : QGraphicsScene(parent) - , isZooming(false) - , m_timeline(timeline) - , m_scale(1.0, 1.0) - , m_editMode(TimelineMode::NormalEdit) -{ -} - -CustomTrackScene::~CustomTrackScene() -{ -} - -double CustomTrackScene::getSnapPointForPos(double pos, bool doSnap) -{ - if (doSnap) { - double maximumOffset; - if (m_scale.x() > 3) { - maximumOffset = 10 / m_scale.x(); - } else { - maximumOffset = 6 / m_scale.x(); - } - for (int i = 0; i < m_snapPoints.size(); ++i) { - if (qAbs((int)(pos - m_snapPoints.at(i).frames(m_timeline->fps()))) < maximumOffset) { - return m_snapPoints.at(i).frames(m_timeline->fps()); - } - if (m_snapPoints.at(i).frames(m_timeline->fps()) > pos) { - break; - } - } - } - return GenTime(pos, m_timeline->fps()).frames(m_timeline->fps()); -} - -void CustomTrackScene::setSnapList(const QList &snaps) -{ - m_snapPoints = snaps; -} - -GenTime CustomTrackScene::previousSnapPoint(const GenTime &pos) const -{ - for (int i = 0; i < m_snapPoints.size(); ++i) { - if (m_snapPoints.at(i) >= pos) { - if (i == 0) { - return GenTime(); - } - return m_snapPoints.at(i - 1); - } - } - return GenTime(); -} - -GenTime CustomTrackScene::nextSnapPoint(const GenTime &pos) const -{ - for (const GenTime &seekPoint : m_snapPoints) { - if (seekPoint > pos) { - return seekPoint; - } - } - return pos; -} - -void CustomTrackScene::setScale(double scale, double vscale) -{ - m_scale.setX(scale); - m_scale.setY(vscale); -} - -QPointF CustomTrackScene::scale() const -{ - return m_scale; -} - -int CustomTrackScene::tracksCount() const -{ - // Ignore black track - return m_timeline->visibleTracksCount(); -} - -void CustomTrackScene::setEditMode(TimelineMode::EditMode mode) -{ - m_editMode = mode; -} - -TimelineMode::EditMode CustomTrackScene::editMode() const -{ - return m_editMode; -} diff --git a/src/timeline/customtrackscene.h b/src/timeline/customtrackscene.h deleted file mode 100644 index 68e0c702b..000000000 --- a/src/timeline/customtrackscene.h +++ /dev/null @@ -1,62 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -/** - * @class CustomTrackScene - * @author Jean-Baptiste Mardelle - * @brief Holds all scene properties that need to be used by clip items. - */ - -#ifndef CUSTOMTRACKSCENE_H -#define CUSTOMTRACKSCENE_H - -#include -#include - -#include "definitions.h" -#include "gentime.h" - -class Timeline; - -class CustomTrackScene : public QGraphicsScene -{ - Q_OBJECT - -public: - explicit CustomTrackScene(Timeline *timeline, QObject *parent = nullptr); - ~CustomTrackScene(); - void setSnapList(const QList &snaps); - GenTime previousSnapPoint(const GenTime &pos) const; - GenTime nextSnapPoint(const GenTime &pos) const; - double getSnapPointForPos(double pos, bool doSnap = true); - void setScale(double scale, double vscale); - QPointF scale() const; - int tracksCount() const; - void setEditMode(TimelineMode::EditMode mode); - TimelineMode::EditMode editMode() const; - bool isZooming; - -private: - Timeline *m_timeline; - QPointF m_scale; - TimelineMode::EditMode m_editMode; - QList m_snapPoints; -}; - -#endif diff --git a/src/timeline/customtrackview.cpp b/src/timeline/customtrackview.cpp deleted file mode 100644 index 0e89464d2..000000000 --- a/src/timeline/customtrackview.cpp +++ /dev/null @@ -1,9125 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "customtrackview.h" -#include "abstractgroupitem.h" -#include "bin/projectclip.h" -#include "clipdurationdialog.h" -#include "clipitem.h" -#include "core.h" -#include "definitions.h" -#include "dialogs/profilesdialog.h" -#include "doc/docundostack.hpp" -#include "effectslist/initeffects.h" -#include "effectstack/widgets/keyframeimport.h" -#include "kdenlivesettings.h" -#include "lib/audio/audioCorrelation.h" -#include "lib/audio/audioEnvelope.h" -#include "mainwindow.h" -#include "managers/guidemanager.h" -#include "managers/movemanager.h" -#include "managers/razormanager.h" -#include "managers/resizemanager.h" -#include "managers/selectmanager.h" -#include "managers/spacermanager.h" -#include "managers/trimmanager.h" -#include "mltcontroller/clipcontroller.h" -#include "mltcontroller/effectscontroller.h" -#include "project/clipmanager.h" -#include "renderer.h" -#include "spacerdialog.h" -#include "timeline.h" -#include "timelinecommands.h" -#include "track.h" -#include "trackdialog.h" -#include "tracksconfigdialog.h" -#include "transition.h" -#include "transitionhandler.h" -#include "ui_addtrack_ui.h" -#include "ui_keyframedialog_ui.h" -#include "utils/KoIconUtils.h" - -#include "kdenlive_debug.h" -#include -#include -#include - -#include -#include -#include -#include -#include -#include -#include - -#include - -#define SEEK_INACTIVE (-1) -//#define DEBUG - -bool sortGuidesList(const Guide *g1, const Guide *g2) -{ - return (*g1).position() < (*g2).position(); -} - -CustomTrackView::CustomTrackView(KdenliveDoc *doc, Timeline *timeline, CustomTrackScene *projectscene, QWidget *parent) - : QGraphicsView(projectscene, parent) - , m_tracksHeight(KdenliveSettings::trackheight()) - , m_projectDuration(0) - , m_cursorPos(0) - , m_cursorOffset(0) - , m_document(doc) - , m_timeline(timeline) - , m_scene(projectscene) - , m_cursorLine(nullptr) - , m_operationMode(None) - , m_moveOpMode(None) - , m_dragItem(nullptr) - , m_dragGuide(nullptr) - , m_visualTip(nullptr) - , m_keyProperties(nullptr) - , m_currentToolManager(nullptr) - , m_autoScroll(KdenliveSettings::autoscroll()) - , m_timelineContextMenu(nullptr) - , m_timelineContextClipMenu(nullptr) - , m_timelineContextTransitionMenu(nullptr) - , m_timelineContextKeyframeMenu(nullptr) - , m_selectKeyframeType(nullptr) - , m_markerMenu(nullptr) - , m_autoTransition(nullptr) - , m_pasteEffectsAction(nullptr) - , m_ungroupAction(nullptr) - , m_editGuide(nullptr) - , m_deleteGuide(nullptr) - , m_clipTypeGroup(nullptr) - , m_clipDrag(false) - , m_findIndex(0) - , m_tool(SelectTool) - , m_copiedItems() - , m_menuPosition() - , m_selectionGroup(nullptr) - , m_selectedTrack(1) - , m_audioCorrelator(nullptr) - , m_audioAlignmentReference(nullptr) -{ - if (doc) { - m_commandStack = doc->commandStack(); - } else { - m_commandStack = nullptr; - } - m_ct = 0; - setMouseTracking(true); - setAcceptDrops(true); - setFrameShape(QFrame::NoFrame); - setLineWidth(0); - // setCacheMode(QGraphicsView::CacheBackground); - setAutoFillBackground(false); - setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate); - setContentsMargins(0, 0, 0, 0); - KColorScheme scheme(palette().currentColorGroup(), KColorScheme::Window, KSharedConfig::openConfig(KdenliveSettings::colortheme())); - m_selectedTrackColor = scheme.background(KColorScheme::ActiveBackground).color(); - m_selectedTrackColor.setAlpha(150); - - m_lockedTrackColor = scheme.background(KColorScheme::NegativeBackground).color(); - m_lockedTrackColor.setAlpha(150); - - m_keyPropertiesTimer = new QTimeLine(800); - m_keyPropertiesTimer->setFrameRange(0, 5); - m_keyPropertiesTimer->setUpdateInterval(100); - m_keyPropertiesTimer->setLoopCount(0); - - m_tipColor = QColor(0, 192, 0, 200); - m_tipPen.setColor(QColor(255, 255, 255, 100)); - m_tipPen.setWidth(3); - - setSceneRect(0, 0, sceneRect().width(), m_tracksHeight); - verticalScrollBar()->setMaximum(m_tracksHeight); - verticalScrollBar()->setTracking(true); - // repaint guides when using vertical scroll - connect(verticalScrollBar(), &QAbstractSlider::valueChanged, this, &CustomTrackView::slotRefreshGuides); - - m_cursorLine = projectscene->addLine(0, 0, 0, m_tracksHeight); - m_cursorLine->setZValue(1000); - QPen pen1 = QPen(); - pen1.setWidth(1); - QColor line(palette().text().color()); - line.setAlpha(100); - pen1.setColor(line); - m_cursorLine->setPen(pen1); - - connect(m_document->renderer(), &Render::prepareTimelineReplacement, this, &CustomTrackView::slotPrepareTimelineReplacement, Qt::DirectConnection); - connect(m_document->renderer(), &Render::replaceTimelineProducer, this, &CustomTrackView::slotReplaceTimelineProducer, Qt::DirectConnection); - connect(m_document->renderer(), &Render::updateTimelineProducer, this, &CustomTrackView::slotUpdateTimelineProducer); - connect(m_document->renderer(), &Render::rendererPosition, this, &CustomTrackView::setCursorPos); - scale(1, 1); - setAlignment(Qt::AlignLeft | Qt::AlignTop); - m_disableClipAction = new QAction(QIcon::fromTheme(QStringLiteral("visibility")), i18n("Disable Clip"), this); - connect(m_disableClipAction, &QAction::triggered, this, &CustomTrackView::disableClip); - m_disableClipAction->setCheckable(true); - m_document->doAddAction(QStringLiteral("clip_disabled"), m_disableClipAction, QKeySequence()); - QAction *pasteAction = m_document->getAction(KStandardAction::name(KStandardAction::Paste)); - if (pasteAction) { - pasteAction->setEnabled(false); - } -} - -CustomTrackView::~CustomTrackView() -{ - qDeleteAll(m_toolManagers); - qDeleteAll(m_guides); - m_guides.clear(); - delete m_keyPropertiesTimer; -} - -void CustomTrackView::initTools() -{ - TrimManager *trim = new TrimManager(this, m_commandStack); - connect(trim, &TrimManager::updateTrimMode, this, &CustomTrackView::updateTrimMode); - m_currentToolManager = new SelectManager(this, m_commandStack); - m_toolManagers.insert(AbstractToolManager::TrimType, trim); - m_toolManagers.insert(AbstractToolManager::SpacerType, new SpacerManager(this, m_commandStack)); - m_toolManagers.insert(AbstractToolManager::ResizeType, new ResizeManager(this, m_commandStack)); - - AbstractToolManager *razorManager = new RazorManager(this, m_commandStack); - m_toolManagers.insert(AbstractToolManager::RazorType, razorManager); - connect(horizontalScrollBar(), &QAbstractSlider::valueChanged, razorManager, &AbstractToolManager::updateTimelineItems); - m_toolManagers.insert(AbstractToolManager::MoveType, new MoveManager(m_timeline->transitionHandler, this, m_commandStack)); - m_toolManagers.insert(AbstractToolManager::SelectType, m_currentToolManager); - m_toolManagers.insert(AbstractToolManager::GuideType, new GuideManager(this, m_commandStack)); - emit updateTrimMode(); -} - -// virtual -void CustomTrackView::keyPressEvent(QKeyEvent *event) -{ - switch (event->key()) { - case Qt::Key_Up: - slotTrackUp(); - event->accept(); - break; - case Qt::Key_Down: - slotTrackDown(); - event->accept(); - break; - default: - break; - } - QGraphicsView::keyPressEvent(event); -} - -bool CustomTrackView::event(QEvent *e) -{ - if (e->type() == QEvent::ShortcutOverride) { - TrimManager *mgr = qobject_cast(m_toolManagers.value(AbstractToolManager::TrimType)); - if ((mgr != nullptr) && mgr->trimMode() != NormalTrim) { - if (((QKeyEvent *)e)->key() == Qt::Key_Escape) { - mgr->setTrimMode(NormalTrim); - e->accept(); - return true; - } - } - } - return QGraphicsView::event(e); -} - -void CustomTrackView::setDocumentModified() -{ - m_document->setModified(true); -} - -void CustomTrackView::setContextMenu(QMenu *timeline, QMenu *clip, QMenu *transition, QActionGroup *clipTypeGroup, QMenu *markermenu) -{ - m_clipTypeGroup = clipTypeGroup; - m_timelineContextMenu = timeline; - m_timelineContextClipMenu = clip; - m_timelineContextTransitionMenu = transition; - m_timelineContextClipMenu->addAction(m_disableClipAction); - connect(m_timelineContextTransitionMenu, &QMenu::aboutToHide, this, &CustomTrackView::slotResetMenuPosition); - connect(m_timelineContextMenu, &QMenu::aboutToHide, this, &CustomTrackView::slotResetMenuPosition); - connect(m_timelineContextClipMenu, &QMenu::aboutToHide, this, &CustomTrackView::slotResetMenuPosition); - connect(m_timelineContextTransitionMenu, &QMenu::triggered, this, &CustomTrackView::slotContextMenuActivated); - connect(m_timelineContextMenu, &QMenu::triggered, this, &CustomTrackView::slotContextMenuActivated); - connect(m_timelineContextClipMenu, &QMenu::triggered, this, &CustomTrackView::slotContextMenuActivated); - - m_markerMenu = new QMenu(i18n("Go to marker..."), this); - m_markerMenu->setEnabled(false); - markermenu->addMenu(m_markerMenu); - connect(m_markerMenu, &QMenu::triggered, this, &CustomTrackView::slotGoToMarker); - QList list = m_timelineContextClipMenu->actions(); - for (int i = 0; i < list.count(); ++i) { - if (list.at(i)->data().toString() == QLatin1String("paste_effects")) { - m_pasteEffectsAction = list.at(i); - } else if (list.at(i)->data().toString() == QLatin1String("ungroup_clip")) { - m_ungroupAction = list.at(i); - } else if (list.at(i)->data().toString() == QLatin1String("A")) { - m_audioActions.append(list.at(i)); - } else if (list.at(i)->data().toString() == QLatin1String("A+V")) { - m_avActions.append(list.at(i)); - } - } - list = m_timelineContextTransitionMenu->actions(); - for (int i = 0; i < list.count(); ++i) { - if (list.at(i)->data().toString() == QLatin1String("auto")) { - m_autoTransition = list.at(i); - break; - } - } - - m_timelineContextMenu->addSeparator(); - m_deleteGuide = new QAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete Guide"), this); - connect(m_deleteGuide, &QAction::triggered, this, &CustomTrackView::slotDeleteTimeLineGuide); - m_timelineContextMenu->addAction(m_deleteGuide); - - m_editGuide = new QAction(QIcon::fromTheme(QStringLiteral("document-properties")), i18n("Edit Guide"), this); - connect(m_editGuide, &QAction::triggered, this, &CustomTrackView::slotEditTimeLineGuide); - m_timelineContextMenu->addAction(m_editGuide); -} - -void CustomTrackView::slotDoResetMenuPosition() -{ - m_menuPosition = QPoint(); -} - -void CustomTrackView::slotResetMenuPosition() -{ - // after a short time (so that the action is triggered / or menu is closed, we reset the menu pos - QTimer::singleShot(300, this, &CustomTrackView::slotDoResetMenuPosition); -} - -void CustomTrackView::slotContextMenuActivated() -{ - // Menu disappeared, restore default operation mode - m_operationMode = None; -} - -void CustomTrackView::checkAutoScroll() -{ - m_autoScroll = KdenliveSettings::autoscroll(); -} - -int CustomTrackView::getFrameWidth() const -{ - return (int)(m_tracksHeight * pCore->getCurrentDar() + 0.5); -} - -void CustomTrackView::updateSceneFrameWidth(double fpsChanged) -{ - int frameWidth = getFrameWidth(); - if (fpsChanged != 1.0 && m_projectDuration > 0) { - - } else { - QList itemList = items(); - ClipItem *item; - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget) { - item = static_cast(itemList.at(i)); - item->resetFrameWidth(frameWidth); - } - } - } -} - -bool CustomTrackView::checkTrackHeight(bool force) -{ - if (!force && m_tracksHeight == KdenliveSettings::trackheight() && sceneRect().height() == m_tracksHeight * m_timeline->visibleTracksCount()) { - return false; - } - int frameWidth = getFrameWidth(); - if (m_tracksHeight != KdenliveSettings::trackheight()) { - QList itemList = items(); - ClipItem *item; - Transition *transitionitem; - m_tracksHeight = KdenliveSettings::trackheight(); - // Remove all items, and re-add them one by one to avoid collisions - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget || itemList.at(i)->type() == TransitionWidget) { - m_scene->removeItem(itemList.at(i)); - } - } - bool snap = KdenliveSettings::snaptopoints(); - KdenliveSettings::setSnaptopoints(false); - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget) { - item = static_cast(itemList.at(i)); - item->setRect(0, 0, item->rect().width(), m_tracksHeight - 1); - item->setPos((qreal)item->startPos().frames(pCore->getCurrentFps()), getPositionFromTrack(item->track()) + 1); - m_scene->addItem(item); - item->resetFrameWidth(frameWidth); - } else if (itemList.at(i)->type() == TransitionWidget) { - transitionitem = static_cast(itemList.at(i)); - transitionitem->setRect(0, 0, transitionitem->rect().width(), m_tracksHeight / 3 * 2 - 1); - transitionitem->setPos((qreal)transitionitem->startPos().frames(pCore->getCurrentFps()), - getPositionFromTrack(transitionitem->track()) + transitionitem->itemOffset()); - m_scene->addItem(transitionitem); - } - } - KdenliveSettings::setSnaptopoints(snap); - } - setSceneRect(0, 0, sceneRect().width(), m_tracksHeight * m_timeline->visibleTracksCount()); - double newHeight = m_tracksHeight * m_timeline->visibleTracksCount() * matrix().m22(); - if ((m_cursorLine->flags() & static_cast((QGraphicsItem::ItemIgnoresTransformations) != 0)) != 0) { - m_cursorLine->setLine(0, 0, 0, newHeight - 1); - } else { - m_cursorLine->setLine(0, 0, 0, m_tracksHeight * m_timeline->visibleTracksCount() - 1); - } - m_currentToolManager->updateTimelineItems(); - for (int i = 0; i < m_guides.count(); ++i) { - m_guides.at(i)->setLine(0, 0, 0, newHeight - 1); - } - viewport()->update(); - return true; -} - -/** Zoom or move viewport on mousewheel - * - * If mousewheel+Ctrl, zooms in/out on the timeline. - * - * With Ctrl, moves viewport towards end of timeline if down/back, - * opposite on up/forward. - * - * See also http://www.kdenlive.org/mantis/view.php?id=265 */ -void CustomTrackView::wheelEvent(QWheelEvent *e) -{ - if (e->modifiers() == Qt::ControlModifier) { - if (m_moveOpMode == None || m_moveOpMode == WaitingForConfirm || m_moveOpMode == ZoomTimeline) { - if (e->delta() > 0) { - emit zoomIn(true); - } else { - emit zoomOut(true); - } - } - } else if (e->modifiers() == Qt::AltModifier) { - if (m_moveOpMode == None || m_moveOpMode == WaitingForConfirm || m_moveOpMode == ZoomTimeline) { - if (e->delta() > 0) { - slotSeekToNextSnap(); - } else { - slotSeekToPreviousSnap(); - } - } - } else { - if (m_moveOpMode == ResizeStart || m_moveOpMode == ResizeEnd) { - // Don't allow scg + resizing - return; - } - if (m_operationMode == None || m_operationMode == ZoomTimeline) { - // Prevent unwanted object move - m_scene->isZooming = true; - } - if (e->delta() <= 0) { - horizontalScrollBar()->setValue(horizontalScrollBar()->value() + horizontalScrollBar()->singleStep()); - } else { - horizontalScrollBar()->setValue(horizontalScrollBar()->value() - horizontalScrollBar()->singleStep()); - } - if (m_operationMode == None || m_operationMode == ZoomTimeline) { - m_scene->isZooming = false; - } - } -} - -int CustomTrackView::getPreviousVideoTrack(int track) -{ - int i = track - 1; - for (; i > 0; i--) { - if (m_timeline->getTrackInfo(i).type == VideoTrack) { - break; - } - } - return i; -} - -int CustomTrackView::getNextVideoTrack(int track) -{ - for (; track < m_timeline->visibleTracksCount(); track++) { - if (m_timeline->getTrackInfo(track).type == VideoTrack) { - break; - } - } - return track; -} - -void CustomTrackView::slotCheckPositionScrolling() -{ - // If mouse is at a border of the view, scroll - if (m_moveOpMode != Seek) { - return; - } - if (mapFromScene(m_cursorPos, 0).x() < 3) { - if (horizontalScrollBar()->value() == 0) { - return; - } - horizontalScrollBar()->setValue(horizontalScrollBar()->value() - 2); - QTimer::singleShot(200, this, &CustomTrackView::slotCheckPositionScrolling); - seekCursorPos(mapToScene(QPoint(-2, 0)).x()); - } else if (viewport()->width() - 3 < mapFromScene(m_cursorPos + 1, 0).x()) { - horizontalScrollBar()->setValue(horizontalScrollBar()->value() + 2); - seekCursorPos(mapToScene(QPoint(viewport()->width(), 0)).x() + 1); - QTimer::singleShot(200, this, &CustomTrackView::slotCheckPositionScrolling); - } -} - -void CustomTrackView::slotAlignPlayheadToMousePos() -{ - /* get curser point ref in screen coord */ - QPoint ps = QCursor::pos(); - /* get xPos in scene coord */ - int mappedXPos = qMax((int)(mapToScene(mapFromGlobal(ps)).x() + 0.5), 0); - /* move playhead to new xPos*/ - seekCursorPos(mappedXPos); -} - -int CustomTrackView::getMousePos() const -{ - return qMax((int)(mapToScene(mapFromGlobal(QCursor::pos())).x() + 0.5), 0); -} - -void CustomTrackView::spaceToolMoveToSnapPos(double snappedPos) -{ - // Make sure there is no collision - QList children = m_selectionGroup->childItems(); - QPainterPath shape = m_selectionGroup->clipGroupSpacerShape(QPointF(snappedPos - m_selectionGroup->sceneBoundingRect().left(), 0)); - QList collidingItems = scene()->items(shape, Qt::IntersectsItemShape); - collidingItems.removeAll(m_selectionGroup); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() == GroupWidget) { - QList subchildren = children.at(i)->childItems(); - for (int j = 0; j < subchildren.count(); ++j) { - collidingItems.removeAll(subchildren.at(j)); - } - } - collidingItems.removeAll(children.at(i)); - } - bool collision = false; - int offset = 0; - for (int i = 0; i < collidingItems.count(); ++i) { - if (!collidingItems.at(i)->isEnabled()) { - continue; - } - if (collidingItems.at(i)->type() == AVWidget && snappedPos < m_selectionGroup->sceneBoundingRect().left()) { - AbstractClipItem *item = static_cast(collidingItems.at(i)); - // Moving backward, determine best pos - QPainterPath clipPath; - clipPath.addRect(item->sceneBoundingRect()); - QPainterPath res = shape.intersected(clipPath); - offset = qMax(offset, (int)(res.boundingRect().width() + 0.5)); - } - } - snappedPos += offset; - // make sure we have no collision - shape = m_selectionGroup->clipGroupSpacerShape(QPointF(snappedPos - m_selectionGroup->sceneBoundingRect().left(), 0)); - collidingItems = scene()->items(shape, Qt::IntersectsItemShape); - collidingItems.removeAll(m_selectionGroup); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() == GroupWidget) { - QList subchildren = children.at(i)->childItems(); - for (int j = 0; j < subchildren.count(); ++j) { - collidingItems.removeAll(subchildren.at(j)); - } - } - collidingItems.removeAll(children.at(i)); - } - - for (int i = 0; i < collidingItems.count(); ++i) { - if (!collidingItems.at(i)->isEnabled()) { - continue; - } - if (collidingItems.at(i)->type() == AVWidget) { - collision = true; - break; - } - } - - if (!collision) { - // Check transitions - shape = m_selectionGroup->transitionGroupShape(QPointF(snappedPos - m_selectionGroup->sceneBoundingRect().left(), 0)); - collidingItems = scene()->items(shape, Qt::IntersectsItemShape); - collidingItems.removeAll(m_selectionGroup); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() == GroupWidget) { - QList subchildren = children.at(i)->childItems(); - for (int j = 0; j < subchildren.count(); ++j) { - collidingItems.removeAll(subchildren.at(j)); - } - } - collidingItems.removeAll(children.at(i)); - } - offset = 0; - - for (int i = 0; i < collidingItems.count(); ++i) { - if (collidingItems.at(i)->type() == TransitionWidget && snappedPos < m_selectionGroup->sceneBoundingRect().left()) { - AbstractClipItem *item = static_cast(collidingItems.at(i)); - // Moving backward, determine best pos - QPainterPath clipPath; - clipPath.addRect(item->sceneBoundingRect()); - QPainterPath res = shape.intersected(clipPath); - offset = qMax(offset, (int)(res.boundingRect().width() + 0.5)); - } - } - - snappedPos += offset; - // make sure we have no collision - shape = m_selectionGroup->transitionGroupShape(QPointF(snappedPos - m_selectionGroup->sceneBoundingRect().left(), 0)); - collidingItems = scene()->items(shape, Qt::IntersectsItemShape); - collidingItems.removeAll(m_selectionGroup); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() == GroupWidget) { - QList subchildren = children.at(i)->childItems(); - for (int j = 0; j < subchildren.count(); ++j) { - collidingItems.removeAll(subchildren.at(j)); - } - } - collidingItems.removeAll(children.at(i)); - } - for (int i = 0; i < collidingItems.count(); ++i) { - if (collidingItems.at(i)->type() == TransitionWidget) { - collision = true; - break; - } - } - } - - if (!collision) { - m_selectionGroup->setTransform(QTransform::fromTranslate(snappedPos - m_selectionGroup->sceneBoundingRect().left(), 0), true); - } -} - -// virtual -void CustomTrackView::mouseMoveEvent(QMouseEvent *event) -{ - int mappedXPos = qMax((int)(mapToScene(event->pos()).x()), 0); - emit mousePosition(mappedXPos); - - if (m_moveOpMode == Seek && event->buttons() != Qt::NoButton) { - QGraphicsView::mouseMoveEvent(event); - if (mappedXPos != m_document->renderer()->getCurrentSeekPosition() && mappedXPos != cursorPos()) { - seekCursorPos(mappedXPos); - slotCheckPositionScrolling(); - } - return; - } - - if (m_moveOpMode == ScrollTimeline) { - QGraphicsView::mouseMoveEvent(event); - return; - } - if ((event->buttons() & Qt::MidButton) != 0u) { - return; - } - if (m_moveOpMode == RubberSelection) { - QGraphicsView::mouseMoveEvent(event); - return; - } - - if (m_moveOpMode == WaitingForConfirm && event->buttons() != Qt::NoButton) { - bool move = (event->pos() - m_clickEvent).manhattanLength() >= QApplication::startDragDistance(); - if (move) { - m_moveOpMode = m_operationMode; - } - } - - QList itemList = items(event->pos()); - QGraphicsRectItem *item = nullptr; - - bool abort = false; - GuideManager::checkOperation(itemList, this, event, m_operationMode, abort); - if (abort) { - return; - } - - if (!abort) { - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget || itemList.at(i)->type() == TransitionWidget) { - item = (QGraphicsRectItem *)itemList.at(i); - break; - } - } - } - switch (m_tool) { - case RazorTool: - RazorManager::checkOperation(item, this, event, mappedXPos, m_operationMode, abort); - break; - case SpacerTool: - break; - case SelectTool: - default: - SelectManager::checkOperation(item, this, event, m_selectionGroup, m_operationMode, m_moveOpMode); - break; - } - - if (!m_currentToolManager->mouseMove(event, mappedXPos, getPositionFromTrack(getTrackFromPos(mapToScene(event->pos()).y())))) { - QGraphicsView::mouseMoveEvent(event); - } -} - -QString CustomTrackView::getDisplayTimecode(const GenTime &time) const -{ - return m_document->timecode().getDisplayTimecode(time, KdenliveSettings::frametimecode()); -} - -QString CustomTrackView::getDisplayTimecodeFromFrames(int frames) const -{ - return m_document->timecode().getDisplayTimecodeFromFrames(frames, KdenliveSettings::frametimecode()); -} - -void CustomTrackView::graphicsViewMouseEvent(QMouseEvent *event) -{ - QGraphicsView::mouseMoveEvent(event); -} - -void CustomTrackView::createRectangleSelection(Qt::KeyboardModifiers modifiers) -{ - setDragMode(QGraphicsView::RubberBandDrag); - setViewportUpdateMode(QGraphicsView::FullViewportUpdate); - if (!(modifiers & Qt::ControlModifier)) { - resetSelectionGroup(); - if (m_dragItem) { - emit clipItemSelected(nullptr); - m_dragItem->setMainSelectedClip(false); - m_dragItem = nullptr; - } - scene()->clearSelection(); - } - m_moveOpMode = RubberSelection; -} - -QList CustomTrackView::selectAllItemsToTheRight(int x) -{ - QRectF r = m_scene->sceneRect(); - r.setLeft(x); - return m_scene->items(r); -} - -int CustomTrackView::spaceToolSelectTrackOnly(int track, QList &selection, GenTime pos) -{ - if (m_timeline->getTrackInfo(track).isLocked) { - // Cannot use spacer on locked track - emit displayMessage(i18n("Cannot use spacer in a locked track"), ErrorMessage); - return -1; - } - QRectF rect; - if (pos > GenTime()) { - rect = QRectF(pos.frames(pCore->getCurrentFps()), getPositionFromTrack(track) + m_tracksHeight / 2, - sceneRect().width() - pos.frames(pCore->getCurrentFps()), m_tracksHeight / 2 - 2); - } else { - rect = QRectF(mapToScene(m_clickEvent).x(), getPositionFromTrack(track) + m_tracksHeight / 2, sceneRect().width() - mapToScene(m_clickEvent).x(), - m_tracksHeight / 2 - 2); - } - bool isOk; - selection = checkForGroups(rect, &isOk); - if (!isOk) { - // groups found on track, do not allow the move - emit displayMessage(i18n("Cannot use spacer in a track with a group"), ErrorMessage); - return -1; - } - // qCDebug(KDENLIVE_LOG) << "SPACER TOOL + CTRL, SELECTING ALL CLIPS ON TRACK " << track << " WITH SELECTION RECT " << m_clickEvent.x() << '/' << track * - // m_tracksHeight + 1 << "; " << mapFromScene(sceneRect().width(), 0).x() - m_clickEvent.x() << '/' << m_tracksHeight - 2; - return 0; -} - -GenTime CustomTrackView::createGroupForSelectedItems(QList &selection) -{ - QList offsetList; - // create group to hold selected items - m_selectionMutex.lock(); - m_selectionGroup = new AbstractGroupItem(pCore->getCurrentFps()); - scene()->addItem(m_selectionGroup); - - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->parentItem() == nullptr && (selection.at(i)->type() == AVWidget || selection.at(i)->type() == TransitionWidget)) { - AbstractClipItem *item = static_cast(selection.at(i)); - if (item->isItemLocked()) { - continue; - } - offsetList.append(item->startPos()); - offsetList.append(item->endPos()); - m_selectionGroup->addItem(selection.at(i)); - } else if (selection.at(i)->type() == GroupWidget) { - if (static_cast(selection.at(i))->isItemLocked()) { - continue; - } - QList children = selection.at(i)->childItems(); - for (int j = 0; j < children.count(); ++j) { - AbstractClipItem *item = static_cast(children.at(j)); - offsetList.append(item->startPos()); - offsetList.append(item->endPos()); - } - m_selectionGroup->addItem(selection.at(i)); - } else if ((selection.at(i)->parentItem() != nullptr) && !selection.contains(selection.at(i)->parentItem())) { - if (static_cast(selection.at(i)->parentItem())->isItemLocked()) { - continue; - } - m_selectionGroup->addItem(selection.at(i)->parentItem()); - } - } - m_selectionMutex.unlock(); - if (!offsetList.isEmpty()) { - qSort(offsetList); - QList cleandOffsetList; - GenTime startOffset = offsetList.takeFirst(); - for (int k = 0; k < offsetList.size(); ++k) { - GenTime newoffset = offsetList.at(k) - startOffset; - if (newoffset != GenTime() && !cleandOffsetList.contains(newoffset)) { - cleandOffsetList.append(newoffset); - } - } - updateSnapPoints(nullptr, cleandOffsetList, true); - } - return m_selectionGroup->startPos(); -} - -void CustomTrackView::updateTimelineSelection() -{ - if (m_dragItem) { - m_dragItem->setZValue(99); - if (m_dragItem->parentItem()) { - m_dragItem->parentItem()->setZValue(99); - } - - // clip selected, update effect stack - if (m_dragItem->type() == AVWidget && !m_dragItem->isItemLocked()) { - ClipItem *selected = static_cast(m_dragItem); - emit clipItemSelected(selected, false); - } else { - emit clipItemSelected(nullptr); - } - if (m_dragItem->type() == TransitionWidget && m_dragItem->isEnabled()) { - // update transition menu action - m_autoTransition->setChecked(static_cast(m_dragItem)->isAutomatic()); - m_autoTransition->setEnabled(true); - // A transition is selected - QPoint p; - ClipItem *transitionClip = getClipItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track); - if ((transitionClip != nullptr) && (transitionClip->binClip() != nullptr)) { - int frameWidth = transitionClip->binClip()->getProducerIntProperty(QStringLiteral("meta.media.width")); - int frameHeight = transitionClip->binClip()->getProducerIntProperty(QStringLiteral("meta.media.height")); - double factor = transitionClip->binClip()->getProducerProperty(QStringLiteral("aspect_ratio")).toDouble(); - if (factor == 0) { - factor = 1.0; - } - p.setX((int)(frameWidth * factor + 0.5)); - p.setY(frameHeight); - } - emit transitionItemSelected(static_cast(m_dragItem), getPreviousVideoTrack(m_dragItem->track()), p); - } else { - emit transitionItemSelected(nullptr); - m_autoTransition->setEnabled(false); - } - } else { - emit clipItemSelected(nullptr); - emit transitionItemSelected(nullptr); - m_autoTransition->setEnabled(false); - } -} - -// virtual -void CustomTrackView::mousePressEvent(QMouseEvent *event) -{ - emit activateDocumentMonitor(); - setFocus(Qt::MouseFocusReason); - m_menuPosition = QPoint(); - if (m_moveOpMode == MoveOperation) { - // click while dragging, ignore - event->ignore(); - return; - } - m_moveOpMode = WaitingForConfirm; - m_clipDrag = false; - - // special cases (middle click button or ctrl / shift click) - if (event->button() == Qt::MidButton) { - if (m_operationMode == KeyFrame) { - if (m_dragItem->type() == AVWidget) { - ClipItem *item = static_cast(m_dragItem); - m_dragItem->insertKeyframe(item->getEffectAtIndex(item->selectedEffectIndex()), m_dragItem->selectedKeyFramePos(), - -1, true); - m_dragItem->update(); - } - } else { - emit playMonitor(); - m_operationMode = None; - } - return; - } - - m_dragGuide = nullptr; - m_clickEvent = event->pos(); - - // check item under mouse - QList collisionList = items(m_clickEvent); - if (event->button() == Qt::LeftButton && event->modifiers() == Qt::ControlModifier && m_tool != SpacerTool && collisionList.isEmpty()) { - // Pressing Ctrl + left mouse button in an empty area scrolls the timeline - setDragMode(QGraphicsView::ScrollHandDrag); - m_moveOpMode = ScrollTimeline; - QGraphicsView::mousePressEvent(event); - return; - } - - if (event->button() == Qt::LeftButton && m_toolManagers.value(AbstractToolManager::GuideType)->mousePress(event, ItemInfo(), collisionList)) { - QGraphicsView::mousePressEvent(event); - if (m_currentToolManager->type() != AbstractToolManager::GuideType) { - m_currentToolManager->closeTool(); - m_currentToolManager = m_toolManagers.value(AbstractToolManager::GuideType); - } - return; - } - - // Find first clip, transition or group under mouse (when no guides selected) - int ct = 0; - AbstractGroupItem *dragGroup = nullptr; - AbstractClipItem *collisionClip = nullptr; - bool found = false; - QList lockedTracks; - double yOffset = 0; - m_selectionMutex.lock(); - while ((m_dragGuide == nullptr) && ct < collisionList.count()) { - if (collisionList.at(ct)->type() == AVWidget || collisionList.at(ct)->type() == TransitionWidget) { - collisionClip = static_cast(collisionList.at(ct)); - if (collisionClip->isItemLocked() || !collisionClip->isEnabled()) { - ct++; - continue; - } - if (collisionClip == m_dragItem) { - collisionClip = nullptr; - } else { - if (m_dragItem) { - m_dragItem->setMainSelectedClip(false); - } - m_dragItem = collisionClip; - m_dragItem->setMainSelectedClip(true); - } - found = true; - bool allowAudioOnly = false; - if (KdenliveSettings::splitaudio() && m_dragItem->type() == AVWidget) { - ClipItem *clp = static_cast(m_dragItem); - if (clp) { - if (clp->clipType() == Audio || clp->clipState() == PlaylistState::AudioOnly) { - allowAudioOnly = true; - } - } - } - for (int i = 1; i < m_timeline->tracksCount(); ++i) { - TrackInfo nfo = m_timeline->getTrackInfo(i); - if (nfo.isLocked || (allowAudioOnly && nfo.type == VideoTrack)) { - lockedTracks << i; - } - } - yOffset = mapToScene(m_clickEvent).y() - m_dragItem->scenePos().y(); - m_dragItem->setProperty("y_absolute", yOffset); - m_dragItem->setProperty("locked_tracks", QVariant::fromValue(lockedTracks)); - m_dragItemInfo = m_dragItem->info(); - if (m_selectionGroup) { - m_selectionGroup->setProperty("y_absolute", yOffset); - m_selectionGroup->setProperty("locked_tracks", QVariant::fromValue(lockedTracks)); - } - if ((m_dragItem->parentItem() != nullptr) && m_dragItem->parentItem()->type() == GroupWidget && m_dragItem->parentItem() != m_selectionGroup) { - QGraphicsItem *topGroup = m_dragItem->parentItem(); - while ((topGroup->parentItem() != nullptr) && topGroup->parentItem()->type() == GroupWidget && topGroup->parentItem() != m_selectionGroup) { - topGroup = topGroup->parentItem(); - } - dragGroup = static_cast(topGroup); - dragGroup->setProperty("y_absolute", yOffset); - dragGroup->setProperty("locked_tracks", QVariant::fromValue(lockedTracks)); - } - break; - } - ct++; - } - m_selectionMutex.unlock(); - if (!found) { - if (m_dragItem) { - m_dragItem->setMainSelectedClip(false); - } - m_dragItem = nullptr; - } - - // context menu requested - if (event->button() == Qt::RightButton) { - // Check if we want keyframes context menu - if (!m_dragGuide) { - // check if there is a guide close to mouse click - QList guidesCollisionList = - items(event->pos().x() - 5, event->pos().y(), 10, 2); // a rect of height < 2 does not always collide with the guide - for (int i = 0; i < guidesCollisionList.count(); ++i) { - if (guidesCollisionList.at(i)->type() == GUIDEITEM) { - m_dragGuide = static_cast(guidesCollisionList.at(i)); - break; - } - } - // keep this to support multiple guides context menu in the future (?) - /*if (guidesCollisionList.at(0)->type() != GUIDEITEM) - guidesCollisionList.removeAt(0); - } - if (!guidesCollisionList.isEmpty()) - m_dragGuide = static_cast (guidesCollisionList.at(0));*/ - } - m_menuPosition = m_clickEvent; - /* if (dragGroup == nullptr) { - if (m_dragItem && m_dragItem->parentItem() && m_dragItem->parentItem() != m_selectionGroup) - dragGroup = static_cast (m_dragItem->parentItem()); - } - */ - if (m_dragItem) { - if (!m_dragItem->isSelected()) { - resetSelectionGroup(); - m_scene->clearSelection(); - m_dragItem->setSelected(true); - } - m_dragItem->setZValue(99); - if (m_dragItem->parentItem()) { - m_dragItem->parentItem()->setZValue(99); - } - } - event->accept(); - updateTimelineSelection(); - return; - } - - QPointF clickPoint = mapToScene(event->pos()); - ItemInfo clickInfo; - clickInfo.startPos = GenTime(clickPoint.x(), pCore->getCurrentFps()); - clickInfo.track = getTrackFromPos(clickPoint.y()); - if (m_currentToolManager->type() == AbstractToolManager::SpacerType || m_currentToolManager->type() == AbstractToolManager::RazorType) { - m_currentToolManager->mousePress(event, clickInfo); - return; - } - /*if (event->button() == Qt::LeftButton) { - if (m_tool == SpacerTool) { - m_toolManagers.value(AbstractToolManager::SpacerType)->mousePress(clickInfo, event->modifiers()); - QGraphicsView::mousePressEvent(event); - return; - } - // Razor tool - if (m_tool == RazorTool) { - m_document->renderer()->switchPlay(false); - m_toolManagers.value(AbstractToolManager::RazorType)->mousePress(clickInfo); - event->accept(); - return; - } - }*/ - if (m_dragItem) { - bool itemSelected = false; - bool selected = true; - if (m_dragItem->isSelected()) { - itemSelected = true; - selected = false; - } else if ((m_dragItem->parentItem() != nullptr) && m_dragItem->parentItem()->isSelected()) { - itemSelected = true; - } else if ((dragGroup != nullptr) && dragGroup->isSelected()) { - itemSelected = true; - } - - if (((event->modifiers() & Qt::ControlModifier) != 0u) && m_operationMode != ResizeEnd && m_operationMode != ResizeStart) { - // Handle ctrl click events - resetSelectionGroup(); - m_dragItem->setSelected(selected); - groupSelectedItems(QList(), false, true); - if (selected) { - m_selectionMutex.lock(); - if (m_selectionGroup) { - m_selectionGroup->setProperty("y_absolute", yOffset); - m_selectionGroup->setProperty("locked_tracks", QVariant::fromValue(lockedTracks)); - } - m_selectionMutex.unlock(); - } else { - m_dragItem->setMainSelectedClip(false); - m_dragItem = nullptr; - } - updateTimelineSelection(); - return; - } - - if (!itemSelected) { - // User clicked a non selected item, select it - resetSelectionGroup(false); - m_scene->clearSelection(); - m_dragItem->setSelected(true); - m_dragItem->setZValue(99); - if (m_dragItem->parentItem()) { - m_dragItem->parentItem()->setZValue(99); - } - - if ((m_dragItem != nullptr) && m_dragItem->type() == AVWidget) { - ClipItem *clip = static_cast(m_dragItem); - updateClipTypeActions(dragGroup == nullptr ? clip : nullptr); - m_pasteEffectsAction->setEnabled(m_copiedItems.count() == 1); - } else { - updateClipTypeActions(nullptr); - } - } else { - m_selectionMutex.lock(); - if (m_selectionGroup) { - QList children = m_selectionGroup->childItems(); - for (int i = 0; i < children.count(); ++i) { - children.at(i)->setSelected(itemSelected); - } - m_selectionGroup->setSelected(itemSelected); - } - if (dragGroup) { - dragGroup->setSelected(itemSelected); - } - m_dragItem->setSelected(itemSelected); - m_selectionMutex.unlock(); - } - - m_selectionMutex.lock(); - if (m_selectionGroup) { - m_selectionGroup->setProperty("y_absolute", yOffset); - m_selectionGroup->setProperty("locked_tracks", QVariant::fromValue(lockedTracks)); - } - m_selectionMutex.unlock(); - - updateTimelineSelection(); - } - if (event->button() == Qt::LeftButton) { - if (m_dragItem) { - if ((m_selectionGroup != nullptr) && m_dragItem->parentItem() == m_selectionGroup) { - // all other modes break the selection, so the user probably wants to move it - m_operationMode = MoveOperation; - } else { - if (m_dragItem->rect().width() * transform().m11() < 15) { - // If the item is very small, only allow move - m_operationMode = MoveOperation; - } else { - m_operationMode = m_dragItem->operationMode(m_dragItem->mapFromScene(mapToScene(event->pos())), event->modifiers()); - } - if (m_operationMode == ResizeEnd) { - // FIXME: find a better way to avoid move in ClipItem::itemChange? - m_dragItem->setProperty("resizingEnd", true); - } - } - } else { - m_operationMode = None; - } - } - // Switch to correct tool - if (!m_currentToolManager->isCurrent(m_operationMode)) { - m_currentToolManager->closeTool(); - m_currentToolManager = m_toolManagers.value(m_currentToolManager->getTool(m_operationMode)); - m_currentToolManager->initTool(mapToScene(event->pos()).x()); - } - - // Update snap points - if (m_selectionGroup == nullptr) { - if (m_operationMode == ResizeEnd || m_operationMode == ResizeStart) { - updateSnapPoints(nullptr); - } else { - updateSnapPoints(m_dragItem); - } - } else { - m_selectionMutex.lock(); - QList offsetList; - QList children = m_selectionGroup->childItems(); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() == AVWidget || children.at(i)->type() == TransitionWidget) { - AbstractClipItem *item = static_cast(children.at(i)); - offsetList.append(item->startPos()); - offsetList.append(item->endPos()); - } - } - if (!offsetList.isEmpty()) { - qSort(offsetList); - GenTime startOffset = offsetList.takeFirst(); - QList cleandOffsetList; - for (int k = 0; k < offsetList.size(); ++k) { - GenTime newoffset = offsetList.at(k) - startOffset; - if (newoffset != GenTime() && !cleandOffsetList.contains(newoffset)) { - cleandOffsetList.append(newoffset); - } - } - updateSnapPoints(nullptr, cleandOffsetList, true); - } - m_selectionMutex.unlock(); - } - m_currentToolManager->mousePress(event, m_dragItemInfo); - - QGraphicsView::mousePressEvent(event); - if (m_operationMode == KeyFrame) { - m_dragItem->prepareKeyframeMove(); - return; - } - if (m_operationMode == TransitionStart && event->modifiers() != Qt::ControlModifier) { - ItemInfo info; - info.startPos = m_dragItem->startPos(); - info.track = m_dragItem->track(); - int transitiontrack = getPreviousVideoTrack(info.track); - ClipItem *transitionClip = nullptr; - if (transitiontrack != 0) { - transitionClip = getClipItemAtMiddlePoint(info.startPos.frames(pCore->getCurrentFps()), transitiontrack); - } - if ((transitionClip != nullptr) && transitionClip->endPos() < m_dragItem->endPos()) { - info.endPos = transitionClip->endPos(); - } else { - GenTime transitionDuration(m_document->getFramePos(KdenliveSettings::transition_duration()), pCore->getCurrentFps()); - if (m_dragItem->cropDuration() < transitionDuration) { - info.endPos = m_dragItem->endPos(); - } else { - info.endPos = info.startPos + transitionDuration; - } - } - if (info.endPos == info.startPos) { - info.endPos = info.startPos + GenTime(m_document->getFramePos(KdenliveSettings::transition_duration()), pCore->getCurrentFps()); - } - // Check there is no other transition at that place - double startY = getPositionFromTrack(info.track) + 1 + m_tracksHeight / 2; - QRectF r(info.startPos.frames(pCore->getCurrentFps()), startY, (info.endPos - info.startPos).frames(pCore->getCurrentFps()), m_tracksHeight / 2); - QList selection = m_scene->items(r); - bool transitionAccepted = true; - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == TransitionWidget) { - Transition *tr = static_cast(selection.at(i)); - if (tr->startPos() - info.startPos > GenTime(5, pCore->getCurrentFps())) { - if (tr->startPos() < info.endPos) { - info.endPos = tr->startPos(); - } - } else { - transitionAccepted = false; - } - } - } - if (transitionAccepted) { - slotAddTransition(static_cast(m_dragItem), info, transitiontrack); - } else { - emit displayMessage(i18n("Cannot add transition"), ErrorMessage); - } - } else if (m_operationMode == TransitionEnd && event->modifiers() != Qt::ControlModifier) { - ItemInfo info; - info.endPos = GenTime(m_dragItem->endPos().frames(pCore->getCurrentFps()), pCore->getCurrentFps()); - info.track = m_dragItem->track(); - int transitiontrack = getPreviousVideoTrack(info.track); - ClipItem *transitionClip = nullptr; - if (transitiontrack != 0) { - transitionClip = getClipItemAtMiddlePoint(info.endPos.frames(pCore->getCurrentFps()), transitiontrack); - } - if ((transitionClip != nullptr) && transitionClip->startPos() > m_dragItem->startPos()) { - info.startPos = transitionClip->startPos(); - } else { - GenTime transitionDuration(m_document->getFramePos(KdenliveSettings::transition_duration()), pCore->getCurrentFps()); - if (m_dragItem->cropDuration() < transitionDuration) { - info.startPos = m_dragItem->startPos(); - } else { - info.startPos = info.endPos - transitionDuration; - } - } - if (info.endPos == info.startPos) { - GenTime transitionDuration(m_document->getFramePos(KdenliveSettings::transition_duration()), pCore->getCurrentFps()); - if (info.endPos < transitionDuration) { - info.startPos = GenTime(); - } else { - info.startPos = info.endPos - transitionDuration; - } - } - QDomElement transition = MainWindow::transitions.getEffectByTag(QStringLiteral("luma"), QStringLiteral("dissolve")).cloneNode().toElement(); - EffectsList::setParameter(transition, QStringLiteral("reverse"), QStringLiteral("1")); - - // Check there is no other transition at that place - double startY = getPositionFromTrack(info.track) + 1 + m_tracksHeight / 2; - QRectF r(info.startPos.frames(pCore->getCurrentFps()), startY, (info.endPos - info.startPos).frames(pCore->getCurrentFps()), m_tracksHeight / 2); - QList selection = m_scene->items(r); - bool transitionAccepted = true; - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == TransitionWidget) { - Transition *tr = static_cast(selection.at(i)); - if (info.endPos - tr->endPos() > GenTime(5, pCore->getCurrentFps())) { - if (tr->endPos() > info.startPos) { - info.startPos = tr->endPos(); - } - } else { - transitionAccepted = false; - } - } - } - if (transitionAccepted) { - slotAddTransition(static_cast(m_dragItem), info, transitiontrack, transition); - } else { - emit displayMessage(i18n("Cannot add transition"), ErrorMessage); - } - } -} - -void CustomTrackView::rebuildGroup(int childTrack, const GenTime &childPos) -{ - const QPointF p((int)childPos.frames(pCore->getCurrentFps()), getPositionFromTrack(childTrack) + m_tracksHeight / 2); - QList list = scene()->items(p); - AbstractGroupItem *group = nullptr; - for (int i = 0; i < list.size(); ++i) { - if (!list.at(i)->isEnabled()) { - continue; - } - if (list.at(i)->type() == GroupWidget) { - group = static_cast(list.at(i)); - break; - } - } - rebuildGroup(group); -} - -void CustomTrackView::rebuildGroup(AbstractGroupItem *group) -{ - if (group) { - m_selectionMutex.lock(); - if (group == m_selectionGroup) { - m_selectionGroup = nullptr; - } - QList children = group->childItems(); - m_document->clipManager()->removeGroup(group); - for (int i = 0; i < children.count(); ++i) { - group->removeFromGroup(children.at(i)); - } - scene()->destroyItemGroup(group); - m_selectionMutex.unlock(); - groupSelectedItems(children, group != m_selectionGroup, true); - } -} - -void CustomTrackView::resetSelectionGroup(bool selectItems) -{ - QMutexLocker lock(&m_selectionMutex); - if (m_selectionGroup) { - // delete selection group - bool snap = KdenliveSettings::snaptopoints(); - KdenliveSettings::setSnaptopoints(false); - - QList children = m_selectionGroup->childItems(); - scene()->destroyItemGroup(m_selectionGroup); - m_selectionGroup = nullptr; - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->parentItem() == nullptr) { - if ((children.at(i)->type() == AVWidget || children.at(i)->type() == TransitionWidget)) { - if (!static_cast(children.at(i))->isItemLocked()) { - children.at(i)->setFlag(QGraphicsItem::ItemIsMovable, true); - children.at(i)->setSelected(selectItems); - } - } else if (children.at(i)->type() == GroupWidget) { - children.at(i)->setFlag(QGraphicsItem::ItemIsMovable, true); - children.at(i)->setSelected(selectItems); - } - } - } - KdenliveSettings::setSnaptopoints(snap); - } -} - -GenTime CustomTrackView::groupSelectedItems(QList selection, bool createNewGroup, bool selectNewGroup) -{ - QMutexLocker lock(&m_selectionMutex); - if (m_selectionGroup) { - qCDebug(KDENLIVE_LOG) << "///// ERROR, TRYING TO OVERRIDE EXISTING GROUP"; - return GenTime(); - } - if (selection.isEmpty()) { - selection = m_scene->selectedItems(); - } - // Split groups and items - QSet groupsList; - QSet itemsList; - - for (int i = 0; i < selection.count(); ++i) { - if (selectNewGroup) { - selection.at(i)->setSelected(true); - } - if (selection.at(i)->type() == GroupWidget) { - AbstractGroupItem *it = static_cast(selection.at(i)); - while ((it->parentItem() != nullptr) && it->parentItem()->type() == GroupWidget) { - it = static_cast(it->parentItem()); - } - if ((it == nullptr) || it->isItemLocked()) { - continue; - } - groupsList.insert(it); - } - } - bool lockGroup = false; - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == AVWidget || selection.at(i)->type() == TransitionWidget) { - if ((selection.at(i)->parentItem() != nullptr) && selection.at(i)->parentItem()->type() == GroupWidget) { - AbstractGroupItem *it = static_cast(selection.at(i)->parentItem()); - while ((it->parentItem() != nullptr) && it->parentItem()->type() == GroupWidget) { - it = static_cast(it->parentItem()); - } - if ((it == nullptr) || it->isItemLocked()) { - continue; - } - groupsList.insert(it); - } else { - AbstractClipItem *it = static_cast(selection.at(i)); - if (!it) { - continue; - } - if (it->isItemLocked()) { - lockGroup = true; - } - itemsList.insert(selection.at(i)); - } - } - } - if (itemsList.isEmpty() && groupsList.isEmpty()) { - return GenTime(); - } - if (itemsList.count() == 1 && groupsList.isEmpty()) { - // only one item selected: - QSetIterator it(itemsList); - m_dragItem = static_cast(it.next()); - m_dragItem->setMainSelectedClip(true); - m_dragItem->setSelected(true); - return m_dragItem->startPos(); - } - - QRectF rectUnion; - // Find top left position of selection - for (const QGraphicsItemGroup *value : groupsList) { - rectUnion = rectUnion.united(value->sceneBoundingRect()); - } - for (const QGraphicsItem *value : itemsList) { - rectUnion = rectUnion.united(value->sceneBoundingRect()); - } - bool snap = KdenliveSettings::snaptopoints(); - KdenliveSettings::setSnaptopoints(false); - if (createNewGroup) { - AbstractGroupItem *newGroup = m_document->clipManager()->createGroup(); - newGroup->setPos(rectUnion.left(), rectUnion.top() - 1); - QPointF diff = newGroup->pos(); - newGroup->setTransform(QTransform::fromTranslate(-diff.x(), -diff.y()), true); - // newGroup->translate((int) -rectUnion.left(), (int) -rectUnion.top() + 1); - - // Check if we are trying to include a group in a group - for (QGraphicsItemGroup *value : groupsList) { - newGroup->addItem(value); - } - - for (QGraphicsItemGroup *value : groupsList) { - QList children = value->childItems(); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() == AVWidget || children.at(i)->type() == TransitionWidget) { - itemsList.insert(children.at(i)); - } - } - AbstractGroupItem *grp = static_cast(value); - m_document->clipManager()->removeGroup(grp); - if (grp == m_selectionGroup) { - m_selectionGroup = nullptr; - } - scene()->destroyItemGroup(grp); - } - - for (QGraphicsItem *value : itemsList) { - newGroup->addItem(value); - } - if (lockGroup) { - newGroup->setItemLocked(true); - } - scene()->addItem(newGroup); - KdenliveSettings::setSnaptopoints(snap); - if (selectNewGroup) { - newGroup->setSelected(true); - } - return newGroup->startPos(); - } - m_selectionGroup = new AbstractGroupItem(pCore->getCurrentFps()); - m_selectionGroup->setPos(rectUnion.left(), rectUnion.top() - 1); - QPointF diff = m_selectionGroup->pos(); - // m_selectionGroup->translate((int) - rectUnion.left(), (int) -rectUnion.top() + 1); - m_selectionGroup->setTransform(QTransform::fromTranslate(-diff.x(), -diff.y()), true); - - scene()->addItem(m_selectionGroup); - for (QGraphicsItemGroup *value : groupsList) { - m_selectionGroup->addItem(value); - } - for (QGraphicsItem *value : itemsList) { - m_selectionGroup->addItem(value); - } - KdenliveSettings::setSnaptopoints(snap); - if (m_selectionGroup) { - if (selectNewGroup) { - m_selectionGroup->setSelected(true); - } - return m_selectionGroup->startPos(); - } - - return GenTime(); -} - -void CustomTrackView::mouseDoubleClickEvent(QMouseEvent *event) -{ - // Check if double click on guide - QList collisionList = items(event->pos()); - for (int i = 0; i < collisionList.count(); ++i) { - if (collisionList.at(i)->type() == GUIDEITEM) { - Guide *editGuide = static_cast(collisionList.at(i)); - if (editGuide) { - slotEditGuide(editGuide->info()); - event->accept(); - return; - } - } - } - if ((m_dragItem != nullptr) && m_dragItem->keyframesCount() > 0) { - // add keyframe - GenTime keyFramePos = GenTime((int)(mapToScene(event->pos()).x()), pCore->getCurrentFps()) - m_dragItem->startPos(); // + m_dragItem->cropStart(); - int single = m_dragItem->keyframesCount(); - double val = m_dragItem->getKeyFrameClipHeight(mapToScene(event->pos()).y() - m_dragItem->scenePos().y()); - ClipItem *item = static_cast(m_dragItem); - QDomElement oldEffect = item->selectedEffect().cloneNode().toElement(); - if (single == 1) { - item->insertKeyframe(item->getEffectAtIndex(item->selectedEffectIndex()), - (item->cropStart() + item->cropDuration()).frames(pCore->getCurrentFps()) - 1, -1, true); - } - // QString previous = item->keyframes(item->selectedEffectIndex()); - item->insertKeyframe(item->getEffectAtIndex(item->selectedEffectIndex()), keyFramePos.frames(pCore->getCurrentFps()), - val); - // QString next = item->keyframes(item->selectedEffectIndex()); - QDomElement newEffect = item->selectedEffect().cloneNode().toElement(); - EditEffectCommand *command = - new EditEffectCommand(this, item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false, true); - m_commandStack->push(command); - updateEffect(item->track(), item->startPos(), item->selectedEffect()); - emit clipItemSelected(item, item->selectedEffectIndex() != 0); - } else if ((m_dragItem != nullptr) && !m_dragItem->isItemLocked()) { - editItemDuration(); - } -} - -void CustomTrackView::editItemDuration() -{ - AbstractClipItem *item; - if (m_dragItem) { - item = m_dragItem; - } else { - if (m_scene->selectedItems().count() == 1) { - item = static_cast(m_scene->selectedItems().at(0)); - } else { - if (m_scene->selectedItems().empty()) { - emit displayMessage(i18n("Cannot find clip to edit"), ErrorMessage); - } else { - emit displayMessage(i18n("Cannot edit the duration of multiple items"), ErrorMessage); - } - return; - } - } - - if (!item) { - emit displayMessage(i18n("Cannot find clip to edit"), ErrorMessage); - return; - } - - if (item->type() == GroupWidget || ((item->parentItem() != nullptr) && item->parentItem()->type() == GroupWidget)) { - emit displayMessage(i18n("Cannot edit an item in a group"), ErrorMessage); - return; - } - - if (!item->isItemLocked()) { - GenTime minimum; - GenTime maximum; - if (item->type() == TransitionWidget) { - getTransitionAvailableSpace(item, minimum, maximum); - } else { - getClipAvailableSpace(item, minimum, maximum); - } - - QPointer d = new ClipDurationDialog(item, m_document->timecode(), minimum, maximum, this); - if (d->exec() == QDialog::Accepted) { - ItemInfo clipInfo = item->info(); - ItemInfo startInfo = clipInfo; - if (item->type() == TransitionWidget) { - // move & resize transition - clipInfo.startPos = d->startPos(); - clipInfo.endPos = clipInfo.startPos + d->duration(); - clipInfo.track = item->track(); - auto *command = new MoveTransitionCommand(this, startInfo, clipInfo, true, true); - updateTrackDuration(clipInfo.track, command); - m_commandStack->push(command); - } else { - // move and resize clip - ClipItem *clip = static_cast(item); - auto *moveCommand = new QUndoCommand(); - moveCommand->setText(i18n("Edit clip")); - if (d->duration() < item->cropDuration() || d->cropStart() != clipInfo.cropStart) { - // duration was reduced, so process it first - clipInfo.endPos = clipInfo.startPos + d->duration(); - clipInfo.cropStart = d->cropStart(); - - resizeClip(startInfo, clipInfo); - // TODO: find a way to apply adjusteffect after the resize command was done / undone - new ResizeClipCommand(this, startInfo, clipInfo, false, true, moveCommand); - adjustEffects(clip, startInfo, moveCommand); - } - - if (d->startPos() != clipInfo.startPos) { - startInfo = clipInfo; - clipInfo.startPos = d->startPos(); - clipInfo.endPos = item->endPos() + (clipInfo.startPos - startInfo.startPos); - new MoveClipCommand(this, startInfo, clipInfo, false, true, moveCommand); - } - - if (d->duration() > item->cropDuration()) { - // duration was increased, so process it after move - startInfo = clipInfo; - clipInfo.endPos = clipInfo.startPos + d->duration(); - clipInfo.cropStart = d->cropStart(); - - resizeClip(startInfo, clipInfo); - // TODO: find a way to apply adjusteffect after the resize command was done / undone - new ResizeClipCommand(this, startInfo, clipInfo, false, true, moveCommand); - adjustEffects(clip, startInfo, moveCommand); - } - updateTrackDuration(clipInfo.track, moveCommand); - m_commandStack->push(moveCommand); - } - } - delete d; - } else { - emit displayMessage(i18n("Item is locked"), ErrorMessage); - } -} - -void CustomTrackView::contextMenuEvent(QContextMenuEvent *event) -{ - if (m_operationMode == KeyFrame) { - displayKeyframesMenu(event->globalPos(), m_dragItem); - } else { - displayContextMenu(event->globalPos(), m_dragItem); - } - event->accept(); -} - -void CustomTrackView::displayKeyframesMenu(QPoint pos, AbstractClipItem *clip) -{ - if (!m_timelineContextKeyframeMenu) { - m_timelineContextKeyframeMenu = new QMenu(this); - // Keyframe type widget - m_selectKeyframeType = new KSelectAction(KoIconUtils::themedIcon(QStringLiteral("keyframes")), i18n("Interpolation"), this); - QAction *discrete = new QAction(KoIconUtils::themedIcon(QStringLiteral("discrete")), i18n("Discrete"), this); - discrete->setData((int)mlt_keyframe_discrete); - discrete->setCheckable(true); - m_selectKeyframeType->addAction(discrete); - QAction *linear = new QAction(KoIconUtils::themedIcon(QStringLiteral("linear")), i18n("Linear"), this); - linear->setData((int)mlt_keyframe_linear); - linear->setCheckable(true); - m_selectKeyframeType->addAction(linear); - QAction *curve = new QAction(KoIconUtils::themedIcon(QStringLiteral("smooth")), i18n("Smooth"), this); - curve->setData((int)mlt_keyframe_smooth); - curve->setCheckable(true); - m_selectKeyframeType->addAction(curve); - m_timelineContextKeyframeMenu->addAction(m_selectKeyframeType); - m_attachKeyframeToEnd = new QAction(i18n("Attach keyframe to end"), this); - m_attachKeyframeToEnd->setCheckable(true); - m_timelineContextKeyframeMenu->addAction(m_attachKeyframeToEnd); - connect(m_selectKeyframeType, SIGNAL(triggered(QAction *)), this, SLOT(slotEditKeyframeType(QAction *))); - connect(m_attachKeyframeToEnd, &QAction::triggered, this, &CustomTrackView::slotAttachKeyframeToEnd); - } - m_attachKeyframeToEnd->setChecked(clip->isAttachedToEnd()); - m_selectKeyframeType->setCurrentAction(clip->parseKeyframeActions(m_selectKeyframeType->actions())); - m_timelineContextKeyframeMenu->exec(pos); -} - -void CustomTrackView::slotAttachKeyframeToEnd(bool attach) -{ - ClipItem *item = static_cast(m_dragItem); - QDomElement oldEffect = item->selectedEffect().cloneNode().toElement(); - item->attachKeyframeToEnd(item->getEffectAtIndex(item->selectedEffectIndex()), attach); - QDomElement newEffect = item->selectedEffect().cloneNode().toElement(); - EditEffectCommand *command = - new EditEffectCommand(this, item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false, false); - m_commandStack->push(command); - updateEffect(item->track(), item->startPos(), item->selectedEffect()); - emit clipItemSelected(item, item->selectedEffectIndex() != 0); -} - -void CustomTrackView::slotEditKeyframeType(QAction *action) -{ - int type = action->data().toInt(); - ClipItem *item = static_cast(m_dragItem); - QDomElement oldEffect = item->selectedEffect().cloneNode().toElement(); - item->editKeyframeType(item->getEffectAtIndex(item->selectedEffectIndex()), type); - QDomElement newEffect = item->selectedEffect().cloneNode().toElement(); - EditEffectCommand *command = - new EditEffectCommand(this, item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false, false); - m_commandStack->push(command); - updateEffect(item->track(), item->startPos(), item->selectedEffect()); - emit clipItemSelected(item, item->selectedEffectIndex() != 0); -} - -void CustomTrackView::displayContextMenu(QPoint pos, AbstractClipItem *clip) -{ - /* - bool isGroup = clip != nullptr && clip->parentItem() && clip->parentItem()->type() == GroupWidget && clip->parentItem() != m_selectionGroup; - m_deleteGuide->setEnabled(m_dragGuide != nullptr); - m_editGuide->setEnabled(m_dragGuide != nullptr); - m_markerMenu->clear(); - m_markerMenu->setEnabled(false); - if (clip == nullptr || m_dragGuide) { - m_timelineContextMenu->popup(pos); - } else if (isGroup) { - m_pasteEffectsAction->setEnabled(m_copiedItems.count() == 1); - m_ungroupAction->setEnabled(true); - if (clip->type() == AVWidget) { - ClipItem *item = static_cast (clip); - m_disableClipAction->setChecked(item->clipState() == PlaylistState::Disabled); - } else { - m_disableClipAction->setChecked(false); - } - updateClipTypeActions(nullptr); - m_timelineContextClipMenu->popup(pos); - } else { - m_ungroupAction->setEnabled(false); - if (clip->type() == AVWidget) { - ClipItem *item = static_cast (clip); - m_disableClipAction->setChecked(item->clipState() == PlaylistState::Disabled); - //build go to marker menu - ClipController *controller = m_document->getClipController(item->getBinId()); - if (controller) { - QList markers = controller->commentedSnapMarkers(); - int offset = (item->startPos() - item->cropStart()).frames(pCore->getCurrentFps()); - if (!markers.isEmpty()) { - for (int i = 0; i < markers.count(); ++i) { - int frame = (int) markers.at(i).time().frames(m_document->timecode().fps()); - QString position = m_document->timecode().getTimecode(markers.at(i).time()) + QLatin1Char(' ') + markers.at(i).comment(); - QAction *go = m_markerMenu->addAction(position); - go->setData(frame + offset); - } - } - m_markerMenu->setEnabled(!m_markerMenu->isEmpty()); - } - updateClipTypeActions(item); - m_pasteEffectsAction->setEnabled(m_copiedItems.count() == 1); - m_timelineContextClipMenu->popup(pos); - } else if (clip->type() == TransitionWidget) { - m_timelineContextTransitionMenu->exec(pos); - } - } - */ -} - -void CustomTrackView::activateMonitor() -{ - emit activateDocumentMonitor(); -} - -void CustomTrackView::insertClipCut(const QString &id, int in, int out) -{ - resetSelectionGroup(); - ItemInfo info; - info.startPos = GenTime(); - info.cropStart = GenTime(in, pCore->getCurrentFps()); - info.endPos = GenTime(out - in, pCore->getCurrentFps()); - info.cropDuration = info.endPos - info.startPos; - info.track = 0; - - // Check if clip can be inserted at that position - ItemInfo pasteInfo = info; - pasteInfo.startPos = GenTime(m_cursorPos, pCore->getCurrentFps()); - pasteInfo.endPos = pasteInfo.startPos + info.endPos; - PlaylistState::ClipState state = PlaylistState::Original; - if (KdenliveSettings::splitaudio()) { - if (m_timeline->videoTarget > -1) { - pasteInfo.track = m_timeline->videoTarget; - if (m_timeline->audioTarget == -1) { - state = PlaylistState::VideoOnly; - } - } else if (m_timeline->audioTarget > -1) { - pasteInfo.track = m_timeline->audioTarget; - state = PlaylistState::AudioOnly; - } else { - emit displayMessage(i18n("Please select target track(s) to perform operation"), ErrorMessage); - return; - } - } else { - pasteInfo.track = selectedTrack(); - } - if (m_timeline->getTrackInfo(pasteInfo.track).isLocked) { - emit displayMessage(i18n("Cannot perform operation on a locked track"), ErrorMessage); - return; - } - bool ok = canBePastedTo(pasteInfo, AVWidget); - if (!ok) { - // Cannot be inserted at cursor pos, insert at end of track - int duration = GenTime(m_timeline->track(pasteInfo.track)->length()).frames(pCore->getCurrentFps()); - pasteInfo.startPos = GenTime(duration, pCore->getCurrentFps()); - pasteInfo.endPos = pasteInfo.startPos + info.endPos; - ok = canBePastedTo(pasteInfo, AVWidget); - } - if (!ok) { - emit displayMessage(i18n("Cannot insert clip in timeline"), ErrorMessage); - return; - } - - // Add refresh command for undo - auto *addCommand = new QUndoCommand(); - addCommand->setText(i18n("Add timeline clip")); - new AddTimelineClipCommand(this, id, pasteInfo, EffectsList(), state, true, false, true, addCommand); - - // Automatic audio split - if (KdenliveSettings::splitaudio() && m_timeline->audioTarget > -1 && m_timeline->videoTarget > -1) { - if (!m_timeline->getTrackInfo(m_timeline->audioTarget).isLocked && m_document->getBinClip(id)->isSplittable()) { - splitAudio(false, pasteInfo, m_timeline->audioTarget, addCommand); - } - } else { - updateTrackDuration(pasteInfo.track, addCommand); - } - m_commandStack->push(addCommand); - - selectClip(true, false); -} - -bool CustomTrackView::insertDropClips(const QMimeData *mimeData, const QPoint &pos) -{ - /* - m_clipDrag = mimeData->hasFormat(QStringLiteral("kdenlive/clip")) || mimeData->hasFormat(QStringLiteral("kdenlive/producerslist")); - // This is not a clip drag, maybe effect or other... - if (!m_clipDrag) { - return false; - } - m_scene->clearSelection(); - if (m_dragItem) { - m_dragItem->setMainSelectedClip(false); - } - m_dragItem = nullptr; - resetSelectionGroup(false); - QPointF framePos = mapToScene(pos); - int track = getTrackFromPos(framePos.y()); - QMutexLocker lock(&m_selectionMutex); - if (track <= 0 || track > m_timeline->tracksCount() - 1 || m_timeline->getTrackInfo(track).isLocked) { - return true; - } - if (mimeData->hasFormat(QStringLiteral("kdenlive/clip"))) { - QStringList list = QString(mimeData->data(QStringLiteral("kdenlive/clip"))).split(QLatin1Char(';')); - ProjectClip *clip = m_document->getBinClip(list.at(0)); - if (clip == nullptr) { - // qCDebug(KDENLIVE_LOG) << " WARNING))))))))) CLIP NOT FOUND : " << list.at(0); - return false; - } - if (!clip->isReady()) { - emit displayMessage(i18n("Clip not ready"), ErrorMessage); - return false; - } - - // Check if clip can be inserted at that position - ItemInfo info; - info.startPos = GenTime((int)(framePos.x() + 0.5), pCore->getCurrentFps()); - info.cropStart = GenTime(list.at(1).toInt(), pCore->getCurrentFps()); - info.cropDuration = GenTime(list.at(2).toInt() - list.at(1).toInt() + 1, pCore->getCurrentFps()); - info.endPos = info.startPos + info.cropDuration; - info.track = track; - framePos.setX((int)(framePos.x() + 0.5)); - framePos.setY(getPositionFromTrack(track)); - if (m_scene->editMode() == TimelineMode::NormalEdit && !canBePastedTo(info, AVWidget)) { - return true; - } - QList lockedTracks; - bool allowAudioOnly = false; - if (KdenliveSettings::splitaudio()) { - if (clip->clipType() == Audio) { - allowAudioOnly = true; - } - } - for (int i = 1; i < m_timeline->tracksCount(); ++i) { - TrackInfo nfo = m_timeline->getTrackInfo(i); - if (nfo.isLocked || (allowAudioOnly && nfo.type == VideoTrack)) { - lockedTracks << i; - } - } - if (lockedTracks.contains(track)) { - return false; - } - - m_selectionGroup = new AbstractGroupItem(pCore->getCurrentFps()); - auto *item = new ClipItem(clip, info, pCore->getCurrentFps(), 1.0, 1, getFrameWidth()); - connect(item, &AbstractClipItem::selectItem, this, &CustomTrackView::slotSelectItem); - m_selectionGroup->addItem(item); - - QList offsetList; - offsetList.append(info.endPos); - updateSnapPoints(nullptr, offsetList); - - m_selectionGroup->setProperty("locked_tracks", QVariant::fromValue(lockedTracks)); - m_selectionGroup->setPos(framePos); - scene()->addItem(m_selectionGroup); - m_selectionGroup->setSelected(true); - } else if (mimeData->hasFormat(QStringLiteral("kdenlive/producerslist"))) { - QStringList ids = QString(mimeData->data(QStringLiteral("kdenlive/producerslist"))).split(QLatin1Char(';')); - QList offsetList; - QList infoList; - GenTime start = GenTime((int)(framePos.x() + 0.5), pCore->getCurrentFps()); - framePos.setX((int)(framePos.x() + 0.5)); - framePos.setY(getPositionFromTrack(track)); - - // Check if user dragged a folder - for (int i = 0; i < ids.size(); ++i) { - if (ids.at(i).startsWith(QLatin1String("#"))) { - QString folderId = ids.at(i); - folderId.remove(0, 1); - QStringList clipsInFolder = m_document->getBinFolderClipIds(folderId); - ids.removeAt(i); - for (int j = 0; j < clipsInFolder.count(); j++) { - ids.insert(i + j, clipsInFolder.at(j)); - } - } - } - - // Check if clips can be inserted at that position - bool allowAudioOnly = false; - for (int i = 0; i < ids.size(); ++i) { - const QString &clipData = ids.at(i); - QString clipId = clipData.section(QLatin1Char('/'), 0, 0); - ProjectClip *clip = m_document->getBinClip(clipId); - if ((clip == nullptr) || !clip->isReady()) { - emit displayMessage(i18n("Clip not ready"), ErrorMessage); - return false; - } - ItemInfo info; - info.startPos = start; - if (clipData.contains(QLatin1Char('/'))) { - // this is a clip zone, set in / out - int in = clipData.section(QLatin1Char('/'), 1, 1).toInt(); - int out = clipData.section(QLatin1Char('/'), 2, 2).toInt(); - info.cropStart = GenTime(in, pCore->getCurrentFps()); - info.cropDuration = GenTime(out - in + 1, pCore->getCurrentFps()); - } else { - info.cropDuration = clip->duration(); - } - info.endPos = info.startPos + info.cropDuration; - info.track = track; - infoList.append(info); - start += info.cropDuration; - if (KdenliveSettings::splitaudio() && clip->clipType() == Audio) { - allowAudioOnly = true; - } - } - if (m_scene->editMode() == TimelineMode::NormalEdit && !canBePastedTo(infoList, AVWidget)) { - return true; - } - QList lockedTracks; - bool locked = false; - for (int i = 1; i < m_timeline->tracksCount(); ++i) { - TrackInfo nfo = m_timeline->getTrackInfo(i); - if (nfo.isLocked) { - lockedTracks << i; - } else if (allowAudioOnly && nfo.type == VideoTrack) { - if (track == i) { - locked = true; - } - lockedTracks << i; - } - } - if (locked) { - return false; - } - if (ids.size() > 1) { - m_selectionGroup = new AbstractGroupItem(pCore->getCurrentFps()); - } - start = GenTime(); - for (int i = 0; i < ids.size(); ++i) { - const QString &clipData = ids.at(i); - QString clipId = clipData.section(QLatin1Char('/'), 0, 0); - ProjectClip *clip = m_document->getBinClip(clipId); - ItemInfo info; - info.startPos = start; - if (clipData.contains(QLatin1Char('/'))) { - // this is a clip zone, set in / out - int in = clipData.section(QLatin1Char('/'), 1, 1).toInt(); - int out = clipData.section(QLatin1Char('/'), 2, 2).toInt(); - info.cropStart = GenTime(in, pCore->getCurrentFps()); - info.cropDuration = GenTime(out - in + 1, pCore->getCurrentFps()); - } else { - info.cropDuration = clip->duration(); - } - info.endPos = info.startPos + info.cropDuration; - info.track = 0; - start += info.cropDuration; - offsetList.append(start); - auto *item = new ClipItem(clip, info, pCore->getCurrentFps(), 1.0, 1, getFrameWidth(), true); - connect(item, &AbstractClipItem::selectItem, this, &CustomTrackView::slotSelectItem); - item->setPos(info.startPos.frames(pCore->getCurrentFps()), item->itemOffset()); - if (ids.size() > 1) { - m_selectionGroup->addItem(item); - } else { - m_dragItem = item; - m_dragItem->setMainSelectedClip(true); - } - item->setSelected(true); - } - - updateSnapPoints(nullptr, offsetList); - - if (m_selectionGroup) { - m_selectionGroup->setProperty("locked_tracks", QVariant::fromValue(lockedTracks)); - scene()->addItem(m_selectionGroup); - m_selectionGroup->setPos(framePos); - } else if (m_dragItem) { - m_dragItem->setProperty("locked_tracks", QVariant::fromValue(lockedTracks)); - scene()->addItem(m_dragItem); - m_dragItem->setPos(framePos); - } - // m_selectionGroup->setZValue(10); - } - */ - return true; -} - -void CustomTrackView::dragEnterEvent(QDragEnterEvent *event) -{ - if (insertDropClips(event->mimeData(), event->pos())) { - if (event->source() == this) { - event->setDropAction(Qt::MoveAction); - event->accept(); - } else { - event->setDropAction(Qt::MoveAction); - event->acceptProposedAction(); - } - } else { - QGraphicsView::dragEnterEvent(event); - } -} - -bool CustomTrackView::itemCollision(AbstractClipItem *item, const ItemInfo &newPos) -{ - QRectF shape = QRectF(newPos.startPos.frames(pCore->getCurrentFps()), getPositionFromTrack(newPos.track) + 1, - (newPos.endPos - newPos.startPos).frames(pCore->getCurrentFps()) - 0.02, m_tracksHeight - 1); - QList collindingItems = scene()->items(shape, Qt::IntersectsItemShape); - collindingItems.removeAll(item); - if (collindingItems.isEmpty()) { - return false; - } - for (int i = 0; i < collindingItems.count(); ++i) { - QGraphicsItem *collision = collindingItems.at(i); - if (collision->type() == item->type()) { - // Collision - // qCDebug(KDENLIVE_LOG) << "// COLLISIION DETECTED"; - return true; - } - } - return false; -} - -void CustomTrackView::slotRefreshEffects(ClipItem *clip) -{ - int track = clip->track(); - GenTime pos = clip->startPos(); - if (!m_timeline->track(track)->removeEffect(pos.seconds(), -1, false)) { - emit displayMessage(i18n("Problem deleting effect"), ErrorMessage); - return; - } - bool success = true; - for (int i = 0; i < clip->effectsCount(); ++i) { - if (!m_timeline->track(track)->addEffect(pos.seconds(), EffectsController::getEffectArgs(clip->effect(i)))) { - success = false; - } - } - if (!success) { - emit displayMessage(i18n("Problem adding effect to clip"), ErrorMessage); - } - if (clip->hasVisibleVideo()) { - monitorRefresh(clip->info()); - } -} - -void CustomTrackView::addEffect(int track, GenTime pos, const QDomElement &effect) -{ - if (pos < GenTime()) { - // Add track effect - if (effect.attribute(QStringLiteral("id")) == QLatin1String("speed")) { - emit displayMessage(i18n("Cannot add speed effect to track"), ErrorMessage); - return; - } - clearSelection(); - m_timeline->addTrackEffect(track, effect); - if (effect.attribute(QStringLiteral("type")) != QLatin1String("audio")) { - monitorRefresh(); - } - emit updateTrackEffectState(track); - emit showTrackEffects(track, m_timeline->getTrackInfo(track)); - return; - } - ClipItem *clip = getClipItemAtStart(pos, track); - if (clip) { - // Special case: speed effect - if (effect.attribute(QStringLiteral("id")) == QLatin1String("speed")) { - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - double speed = locale.toDouble(EffectsList::parameter(effect, QStringLiteral("speed"))) / 100.0; - int strobe = EffectsList::parameter(effect, QStringLiteral("strobe")).toInt(); - if (strobe == 0) { - strobe = 1; - } - doChangeClipSpeed(clip->info(), clip->speedIndependantInfo(), clip->clipState(), speed, strobe, clip->getBinId()); - EffectsParameterList params = clip->addEffect(effect); - if (clip->isSelected()) { - emit clipItemSelected(clip); - } - monitorRefresh(clip->info(), true); - return; - } - EffectsParameterList params = clip->addEffect(effect); - if (!m_timeline->track(track)->addEffect(pos.seconds(), params)) { - emit displayMessage(i18n("Problem adding effect to clip"), ErrorMessage); - clip->deleteEffect(params.paramValue(QStringLiteral("kdenlive_ix")).toInt()); - } else { - clip->setSelectedEffect(params.paramValue(QStringLiteral("kdenlive_ix")).toInt()); - if (clip->hasVisibleVideo() && effect.attribute(QStringLiteral("type")) != QLatin1String("audio")) { - monitorRefresh(clip->info(), true); - } - } - if (clip->isMainSelectedClip()) { - emit clipItemSelected(clip); - } - } else { - emit displayMessage(i18n("Cannot find clip to add effect"), ErrorMessage); - } -} - -void CustomTrackView::deleteEffect(int track, const GenTime &pos, const QDomElement &effect) -{ - int index = effect.attribute(QStringLiteral("kdenlive_ix")).toInt(); - if (pos < GenTime()) { - // Delete track effect - if (!m_timeline->removeTrackEffect(track, index, effect)) { - emit displayMessage(i18n("Problem deleting effect"), ErrorMessage); - } - emit updateTrackEffectState(track); - if (effect.attribute(QStringLiteral("type")) != QLatin1String("audio")) { - monitorRefresh(); - } - emit showTrackEffects(track, m_timeline->getTrackInfo(track)); - return; - } - // Special case: speed effect - if (effect.attribute(QStringLiteral("id")) == QLatin1String("speed")) { - ClipItem *clip = getClipItemAtStart(pos, track); - if (clip) { - doChangeClipSpeed(clip->info(), clip->speedIndependantInfo(), clip->clipState(), 1.0, 1, clip->getBinId(), true); - clip->deleteEffect(index); - monitorRefresh(clip->info()); - emit clipItemSelected(clip); - return; - } - } - if (!m_timeline->track(track)->removeEffect(pos.seconds(), index, true)) { - // qCDebug(KDENLIVE_LOG) << "// ERROR REMOV EFFECT: " << index << ", DISABLE: " << effect.attribute("disable"); - emit displayMessage(i18n("Problem deleting effect"), ErrorMessage); - return; - } - ClipItem *clip = getClipItemAtStart(pos, track); - if (clip) { - if (clip->deleteEffect(index) && clip->hasVisibleVideo()) { - monitorRefresh(clip->info(), true); - } - if (clip->isMainSelectedClip()) { - emit clipItemSelected(clip); - } - } -} - -void CustomTrackView::slotAddGroupEffect(const QDomElement &effect, AbstractGroupItem *group, AbstractClipItem *dropTarget) -{ - QList itemList = group->childItems(); - auto *effectCommand = new QUndoCommand(); - QString effectName; - int offset = effect.attribute(QStringLiteral("clipstart")).toInt(); - QDomElement namenode = effect.firstChildElement(QStringLiteral("name")); - if (!namenode.isNull()) { - effectName = i18n(namenode.text().toUtf8().data()); - } else { - effectName = i18n("effect"); - } - effectCommand->setText(i18n("Add %1", effectName)); - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == GroupWidget) { - itemList << itemList.at(i)->childItems(); - } - if (itemList.at(i)->type() == AVWidget) { - ClipItem *item = static_cast(itemList.at(i)); - if (effect.tagName() == QLatin1String("effectgroup")) { - QDomNodeList effectlist = effect.elementsByTagName(QStringLiteral("effect")); - for (int j = 0; j < effectlist.count(); ++j) { - QDomElement subeffect = effectlist.at(j).toElement(); - if (subeffect.hasAttribute(QStringLiteral("kdenlive_info"))) { - // effect is in a group - EffectInfo effectInfo; - effectInfo.fromString(subeffect.attribute(QStringLiteral("kdenlive_info"))); - if (effectInfo.groupIndex < 0) { - // group needs to be appended - effectInfo.groupIndex = item->nextFreeEffectGroupIndex(); - subeffect.setAttribute(QStringLiteral("kdenlive_info"), effectInfo.toString()); - } - } - processEffect(item, subeffect.cloneNode().toElement(), offset, effectCommand); - } - } else { - processEffect(item, effect.cloneNode().toElement(), offset, effectCommand); - } - } - } - if (effectCommand->childCount() > 0) { - m_commandStack->push(effectCommand); - } else { - delete effectCommand; - } - if (dropTarget) { - clearSelection(false); - m_dragItem = dropTarget; - m_dragItem->setSelected(true); - m_dragItem->setMainSelectedClip(true); - emit clipItemSelected(static_cast(dropTarget)); - } -} - -void CustomTrackView::slotAddEffect(ClipItem *clip, const QDomElement &effect, int track) -{ - if (clip == nullptr) { - // Track effect - slotAddTrackEffect(effect, track); - return; - } - slotAddEffect(effect, clip->startPos(), clip->track()); -} - -void CustomTrackView::slotDropEffect(ClipItem *clip, const QDomElement &effect, GenTime pos, int track) -{ - if (clip == nullptr) { - return; - } - slotAddEffect(effect, pos, track); - if (clip->parentItem()) { - // Clip is in a group, should not happen - // qCDebug(KDENLIVE_LOG)<<"/// DROPPED ON ITEM IN GRP"; - } else if (clip != m_dragItem) { - clearSelection(false); - m_dragItem = clip; - m_dragItem->setMainSelectedClip(true); - clip->setSelected(true); - emit clipItemSelected(clip); - } -} - -void CustomTrackView::slotSelectItem(AbstractClipItem *item) -{ - clearSelection(false); - m_dragItem = item; - m_dragItem->setMainSelectedClip(true); - item->setSelected(true); - if (item->type() == AVWidget) { - emit clipItemSelected((ClipItem *)item); - } else if (item->type() == TransitionWidget) { - emit transitionItemSelected((Transition *)item); - } -} - -void CustomTrackView::slotDropTransition(ClipItem *clip, const QDomElement &transition, QPointF scenePos) -{ - if (clip == nullptr) { - return; - } - m_menuPosition = mapFromScene(scenePos); - slotAddTransitionToSelectedClips(transition, QList() << clip); - m_menuPosition = QPoint(); -} - -void CustomTrackView::removeSplitOverlay() -{ - m_timeline->removeSplitOverlay(); -} - -bool CustomTrackView::createSplitOverlay(Mlt::Filter *filter) -{ - if ((m_dragItem == nullptr) || m_dragItem->type() != AVWidget) { - // TODO manage split clip - return false; - } - return m_timeline->createOverlay(filter, m_dragItem->track(), m_dragItem->startPos().frames(pCore->getCurrentFps())); -} - -void CustomTrackView::trimMode(bool enable, int ripplePos) -{ - if (!enable) { - m_timeline->removeSplitOverlay(); - emit loadMonitorScene(MonitorSceneDefault, false); - monitorRefresh(); - return; - } - if ((m_dragItem == nullptr) || m_dragItem->type() != AVWidget) { - qCDebug(KDENLIVE_LOG) << "* * * * *RIPPLEMODE ERROR"; - emit displayMessage(i18n("Select a clip to enter ripple mode"), InformationMessage); - return; - } - if (m_operationMode == ResizeEnd) { - m_moveOpMode = RollingEnd; - } else if (m_operationMode == ResizeStart) { - m_moveOpMode = RollingStart; - } - - if (m_timeline->createRippleWindow(m_dragItem->track(), ripplePos, m_moveOpMode)) { - monitorRefresh(); - } -} - -AbstractToolManager *CustomTrackView::toolManager(AbstractToolManager::ToolManagerType trimType) -{ - return m_toolManagers.value(trimType); -} - -void CustomTrackView::slotAddEffectToCurrentItem(const QDomElement &effect) -{ - slotAddEffect(effect, GenTime(), -1); -} - -void CustomTrackView::slotAddEffect(const QDomElement &effect, const GenTime &pos, int track) -{ - QList itemList; - auto *effectCommand = new QUndoCommand(); - QString effectName; - int offset = effect.attribute(QStringLiteral("clipstart")).toInt(); - if (effect.tagName() == QLatin1String("effectgroup")) { - effectName = effect.attribute(QStringLiteral("name")); - } else { - QDomElement namenode = effect.firstChildElement(QStringLiteral("name")); - if (!namenode.isNull()) { - effectName = i18n(namenode.text().toUtf8().data()); - } else { - effectName = i18n("effect"); - } - } - effectCommand->setText(i18n("Add %1", effectName)); - - if (track == -1) { - itemList = scene()->selectedItems(); - } else if (itemList.isEmpty()) { - ClipItem *clip = getClipItemAtStart(pos, track); - if (clip) { - itemList.append(clip); - } - } - if (itemList.isEmpty()) { - emit displayMessage(i18n("Select a clip if you want to apply an effect"), ErrorMessage); - } - - // expand groups - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == GroupWidget) { - QList subitems = itemList.at(i)->childItems(); - for (int j = 0; j < subitems.count(); ++j) { - if (!itemList.contains(subitems.at(j))) { - itemList.append(subitems.at(j)); - } - } - } - } - - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget) { - ClipItem *item = static_cast(itemList.at(i)); - if (effect.tagName() == QLatin1String("effectgroup")) { - QDomNodeList effectlist = effect.elementsByTagName(QStringLiteral("effect")); - for (int j = 0; j < effectlist.count(); ++j) { - QDomElement subeffect = effectlist.at(j).toElement(); - if (subeffect.hasAttribute(QStringLiteral("kdenlive_info"))) { - // effect is in a group - EffectInfo effectInfo; - effectInfo.fromString(subeffect.attribute(QStringLiteral("kdenlive_info"))); - if (effectInfo.groupIndex < 0) { - // group needs to be appended - effectInfo.groupIndex = item->nextFreeEffectGroupIndex(); - subeffect.setAttribute(QStringLiteral("kdenlive_info"), effectInfo.toString()); - } - } - processEffect(item, subeffect, offset, effectCommand); - } - } else { - processEffect(item, effect, offset, effectCommand); - } - } - } - if (effectCommand->childCount() > 0) { - m_commandStack->push(effectCommand); - } else { - delete effectCommand; - } -} - -void CustomTrackView::processEffect(ClipItem *item, const QDomElement &effect, int offset, QUndoCommand *effectCommand) -{ - if (effect.attribute(QStringLiteral("type")) == QLatin1String("audio")) { - // Don't add audio effects on video clips - if (item->clipState() == PlaylistState::VideoOnly || (item->clipType() != Audio && item->clipType() != AV && item->clipType() != Playlist)) { - /* do not show error message when item is part of a group as the user probably knows what he does then - * and the message is annoying when working with the split audio feature */ - if ((item->parentItem() == nullptr) || item->parentItem() == m_selectionGroup) { - emit displayMessage(i18n("Cannot add an audio effect to this clip"), ErrorMessage); - } - return; - } - } else if (effect.attribute(QStringLiteral("type")) == QLatin1String("video") || !effect.hasAttribute(QStringLiteral("type"))) { - // Don't add video effect on audio clips - if (item->clipState() == PlaylistState::AudioOnly || item->clipType() == Audio) { - /* do not show error message when item is part of a group as the user probably knows what he does then - * and the message is annoying when working with the split audio feature */ - if ((item->parentItem() == nullptr) || item->parentItem() == m_selectionGroup) { - emit displayMessage(i18n("Cannot add a video effect to this clip"), ErrorMessage); - } - return; - } - } - if (effect.attribute(QStringLiteral("unique"), QStringLiteral("0")) != QLatin1String("0") && - item->hasEffect(effect.attribute(QStringLiteral("tag")), effect.attribute(QStringLiteral("id"))) != -1) { - emit displayMessage(i18n("Effect already present in clip"), ErrorMessage); - return; - } - if (item->isItemLocked()) { - return; - } - - if (effect.attribute(QStringLiteral("id")) == QLatin1String("freeze") && m_cursorPos > item->startPos().frames(pCore->getCurrentFps()) && - m_cursorPos < item->endPos().frames(pCore->getCurrentFps())) { - item->initEffect(effect, m_cursorPos - item->startPos().frames(pCore->getCurrentFps()), offset); - } else { - item->initEffect(effect, 0, offset); - } - new AddEffectCommand(this, item->track(), item->startPos(), effect, true, effectCommand); -} - -void CustomTrackView::slotDeleteEffectGroup(ClipItem *clip, int track, const QDomDocument &doc, bool affectGroup) -{ - auto *delCommand = new QUndoCommand(); - QString effectName = doc.documentElement().attribute(QStringLiteral("name")); - delCommand->setText(i18n("Delete %1", effectName)); - QDomNodeList effects = doc.elementsByTagName(QStringLiteral("effect")); - for (int i = 0; i < effects.count(); ++i) { - slotDeleteEffect(clip, track, effects.at(i).toElement(), affectGroup, delCommand); - } - m_commandStack->push(delCommand); -} - -void CustomTrackView::slotDeleteEffect(ClipItem *clip, int track, const QDomElement &effect, bool affectGroup, QUndoCommand *parentCommand) -{ - if (clip == nullptr) { - // delete track effect - AddEffectCommand *command = new AddEffectCommand(this, track, GenTime(-1), effect, false, parentCommand); - if (parentCommand == nullptr) { - m_commandStack->push(command); - } - return; - } - AddEffectCommand *command = nullptr; - if (affectGroup && (clip->parentItem() != nullptr) && clip->parentItem() == m_selectionGroup) { - // clip is in a group, also remove the effect in other clips of the group - QList items = m_selectionGroup->childItems(); - QUndoCommand *delCommand = parentCommand == nullptr ? new QUndoCommand() : parentCommand; - QString effectName; - QDomElement namenode = effect.firstChildElement(QStringLiteral("name")); - if (!namenode.isNull()) { - effectName = i18n(namenode.text().toUtf8().data()); - } else { - effectName = i18n("effect"); - } - delCommand->setText(i18n("Delete %1", effectName)); - - // expand groups - for (int i = 0; i < items.count(); ++i) { - if (items.at(i)->type() == GroupWidget) { - QList subitems = items.at(i)->childItems(); - for (int j = 0; j < subitems.count(); ++j) { - if (!items.contains(subitems.at(j))) { - items.append(subitems.at(j)); - } - } - } - } - - for (int i = 0; i < items.count(); ++i) { - if (items.at(i)->type() == AVWidget) { - ClipItem *item = static_cast(items.at(i)); - int ix = item->hasEffect(effect.attribute(QStringLiteral("tag")), effect.attribute(QStringLiteral("id"))); - if (ix != -1) { - QDomElement eff = item->effectAtIndex(ix); - new AddEffectCommand(this, item->track(), item->startPos(), eff, false, delCommand); - } - } - } - if (parentCommand == nullptr) { - if (delCommand->childCount() > 0) { - m_commandStack->push(delCommand); - } else { - delete delCommand; - } - } - return; - } - command = new AddEffectCommand(this, clip->track(), clip->startPos(), effect, false, parentCommand); - - if (parentCommand == nullptr) { - m_commandStack->push(command); - } -} - -void CustomTrackView::updateEffect(int track, GenTime pos, const QDomElement &insertedEffect, bool updateEffectStack, bool replaceEffect, bool refreshMonitor) -{ - if (insertedEffect.isNull()) { - // qCDebug(KDENLIVE_LOG)<<"// Trying to add null effect"; - emit displayMessage(i18n("Problem editing effect"), ErrorMessage); - return; - } - int ix = insertedEffect.attribute(QStringLiteral("kdenlive_ix")).toInt(); - QDomElement effect = insertedEffect.cloneNode().toElement(); - // qCDebug(KDENLIVE_LOG) << "// update effect ix: " << effect.attribute("kdenlive_ix")<<", TAG: "<< insertedEffect.attribute("tag"); - if (pos < GenTime()) { - // editing a track effect - EffectsParameterList effectParams = EffectsController::getEffectArgs(effect); - // check if we are trying to reset a keyframe effect - /*if (effectParams.hasParam("keyframes") && effectParams.paramValue("keyframes").isEmpty()) { - clip->initEffect(effect); - effectParams = EffectsController::getEffectArgs(effect); - }*/ - if (!m_timeline->track(track)->editTrackEffect(effectParams, replaceEffect)) { - emit displayMessage(i18n("Problem editing effect"), ErrorMessage); - } - m_timeline->setTrackEffect(track, ix, effect); - if (refreshMonitor && effect.attribute(QStringLiteral("type")) != QLatin1String("audio")) { - monitorRefresh(); - } - emit updateTrackEffectState(track); - return; - } - ClipItem *clip = getClipItemAtStart(pos, track); - if (clip) { - // Special case: speed effect - if (effect.attribute(QStringLiteral("id")) == QLatin1String("speed")) { - if (effect.attribute(QStringLiteral("disable")) == QLatin1String("1")) { - doChangeClipSpeed(clip->info(), clip->speedIndependantInfo(), clip->clipState(), 1.0, 1, clip->getBinId()); - } else { - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - double speed = locale.toDouble(EffectsList::parameter(effect, QStringLiteral("speed"))) / 100.0; - int strobe = EffectsList::parameter(effect, QStringLiteral("strobe")).toInt(); - if (strobe == 0) { - strobe = 1; - } - doChangeClipSpeed(clip->info(), clip->speedIndependantInfo(), clip->clipState(), speed, strobe, clip->getBinId()); - } - clip->updateEffect(effect); - if (updateEffectStack && clip->isSelected()) { - emit clipItemSelected(clip); - } - if (ix == clip->selectedEffectIndex()) { - // make sure to update display of clip keyframes - clip->setSelectedEffect(ix); - } - return; - } - - EffectsParameterList effectParams = EffectsController::getEffectArgs(effect); - - // check if we are trying to reset a keyframe effect - if (effectParams.hasParam(QStringLiteral("keyframes")) && effectParams.paramValue(QStringLiteral("keyframes")).isEmpty()) { - clip->initEffect(effect); - effectParams = EffectsController::getEffectArgs(effect); - } - - // Check if a fade effect was changed - QString effectId = effect.attribute(QStringLiteral("id")); - if (effectId == QLatin1String("fadein") || effectId == QLatin1String("fade_from_black") || effectId == QLatin1String("fadeout") || - effectId == QLatin1String("fade_to_black")) { - clip->setSelectedEffect(clip->selectedEffectIndex()); - } - - bool success = m_timeline->track(clip->track())->editEffect(clip->startPos().seconds(), effectParams, replaceEffect); - if (success) { - clip->updateEffect(effect); - if (refreshMonitor && clip->hasVisibleVideo() && effect.attribute(QStringLiteral("type")) != QLatin1String("audio")) { - monitorRefresh(clip->info(), true); - } - if (updateEffectStack && clip->isSelected()) { - emit clipItemSelected(clip); - } - if (ix == clip->selectedEffectIndex()) { - // make sure to update display of clip keyframes - clip->setSelectedEffect(ix); - } - } else { - emit displayMessage(i18n("Problem editing effect"), ErrorMessage); - } - } else { - emit displayMessage(i18n("Cannot find clip to update effect"), ErrorMessage); - } -} - -void CustomTrackView::updateEffectState(int track, GenTime pos, const QList &effectIndexes, bool disable, bool updateEffectStack) -{ - if (pos < GenTime()) { - // editing a track effect - if (!m_timeline->track(track)->enableTrackEffects(effectIndexes, disable)) { - emit displayMessage(i18n("Problem editing effect"), ErrorMessage); - return; - } - if (m_timeline->enableTrackEffects(track, effectIndexes, disable)) { - monitorRefresh(); - } - emit updateTrackEffectState(track); - emit showTrackEffects(track, m_timeline->getTrackInfo(track)); - return; - } - // editing a clip effect - ClipItem *clip = getClipItemAtStart(pos, track); - if (clip) { - bool success = m_timeline->track(clip->track())->enableEffects(clip->startPos().seconds(), effectIndexes, disable); - if (success) { - if (clip->enableEffects(effectIndexes, disable) && clip->hasVisibleVideo()) { - monitorRefresh(clip->info(), true); - } - if (updateEffectStack && clip->isSelected()) { - emit clipItemSelected(clip); - } - if (effectIndexes.contains(clip->selectedEffectIndex())) { - // make sure to update display of clip keyframes - clip->setSelectedEffect(clip->selectedEffectIndex()); - } - } else { - emit displayMessage(i18n("Problem editing effect"), ErrorMessage); - } - } else { - emit displayMessage(i18n("Cannot find clip to update effect"), ErrorMessage); - } -} - -void CustomTrackView::moveEffect(int track, const GenTime &pos, const QList &oldPos, const QList &newPos) -{ - if (pos < GenTime()) { - // Moving track effect - int max = m_timeline->getTrackEffects(track).count(); - int new_position = newPos.at(0); - if (new_position > max) { - new_position = max; - } - int old_position = oldPos.at(0); - for (int i = 0; i < newPos.count(); ++i) { - QDomElement act = m_timeline->getTrackEffect(track, new_position); - if (old_position > new_position) { - // Moving up, we need to adjust index - old_position = oldPos.at(i); - new_position = newPos.at(i); - } - QDomElement before = m_timeline->getTrackEffect(track, old_position); - if (!act.isNull() && !before.isNull()) { - m_timeline->setTrackEffect(track, new_position, before); - m_timeline->track(track)->moveTrackEffect(old_position, new_position); - if (before.attribute(QStringLiteral("type")) != QLatin1String("audio")) { - monitorRefresh(); - m_timeline->invalidateTrack(track); - } - } else { - emit displayMessage(i18n("Cannot move effect"), ErrorMessage); - } - } - emit showTrackEffects(track, m_timeline->getTrackInfo(track)); - return; - } - ClipItem *clip = getClipItemAtStart(pos, track); - if (clip) { - int new_position = newPos.at(0); - if (new_position > clip->effectsCount()) { - new_position = clip->effectsCount(); - } - int old_position = oldPos.at(0); - for (int i = 0; i < newPos.count(); ++i) { - QDomElement act = clip->effectAtIndex(new_position); - if (old_position > new_position) { - // Moving up, we need to adjust index - old_position = oldPos.at(i); - new_position = newPos.at(i); - } - QDomElement before = clip->effectAtIndex(old_position); - if (act.isNull() || before.isNull()) { - emit displayMessage(i18n("Cannot move effect"), ErrorMessage); - return; - } - clip->moveEffect(before, new_position); - if (clip->hasEffect(QStringLiteral("timewarp"), QStringLiteral("speed")) != -1) { - // special case, speed effect is not in MLT's filter list, so decrease indexes - old_position--; - new_position--; - } - // special case: speed effect, which is a pseudo-effect, not appearing in MLT's effects - m_timeline->track(track)->moveEffect(pos.seconds(), old_position, new_position); - if (clip->hasVisibleVideo() && before.attribute(QStringLiteral("type")) != QLatin1String("audio")) { - monitorRefresh(clip->info(), true); - } - } - clip->setSelectedEffect(newPos.at(0)); - emit clipItemSelected(clip); - } else { - emit displayMessage(i18n("Cannot move effect"), ErrorMessage); - } -} - -void CustomTrackView::slotChangeEffectState(ClipItem *clip, int track, QList effectIndexes, bool disable) -{ - ChangeEffectStateCommand *command; - if (clip == nullptr) { - // editing track effect - command = new ChangeEffectStateCommand(this, track, GenTime(-1), effectIndexes, disable, false, true); - } else { - // Check if we have a speed effect, disabling / enabling it needs a special procedure since it is a pseudoo effect - QList speedEffectIndexes; - for (int i = 0; i < effectIndexes.count(); ++i) { - QDomElement effect = clip->effectAtIndex(effectIndexes.at(i)); - if (effect.attribute(QStringLiteral("id")) == QLatin1String("speed")) { - // speed effect - speedEffectIndexes << effectIndexes.at(i); - QDomElement newEffect = effect.cloneNode().toElement(); - newEffect.setAttribute(QStringLiteral("disable"), (int)disable); - EditEffectCommand *editcommand = - new EditEffectCommand(this, clip->track(), clip->startPos(), effect, newEffect, effectIndexes.at(i), false, true, true); - m_commandStack->push(editcommand); - } - } - for (int j = 0; j < speedEffectIndexes.count(); ++j) { - effectIndexes.removeAll(speedEffectIndexes.at(j)); - } - command = new ChangeEffectStateCommand(this, clip->track(), clip->startPos(), effectIndexes, disable, false, true); - } - m_commandStack->push(command); -} - -void CustomTrackView::slotChangeEffectPosition(ClipItem *clip, int track, const QList ¤tPos, int newPos) -{ - MoveEffectCommand *command; - if (clip == nullptr) { - // editing track effect - command = new MoveEffectCommand(this, track, GenTime(-1), currentPos, newPos); - } else { - command = new MoveEffectCommand(this, clip->track(), clip->startPos(), currentPos, newPos); - } - m_commandStack->push(command); -} - -void CustomTrackView::slotUpdateClipEffect(ClipItem *clip, int track, const QDomElement &oldeffect, const QDomElement &effect, int ix, bool refreshEffectStack) -{ - EditEffectCommand *command; - if (clip) { - command = new EditEffectCommand(this, clip->track(), clip->startPos(), oldeffect.cloneNode().toElement(), effect.cloneNode().toElement(), ix, - refreshEffectStack, true, true); - } else { - command = new EditEffectCommand(this, track, GenTime(-1), oldeffect.cloneNode().toElement(), effect.cloneNode().toElement(), ix, refreshEffectStack, - true, true); - } - m_commandStack->push(command); -} - -void CustomTrackView::slotUpdateClipRegion(ClipItem *clip, int ix, const QString ®ion) -{ - QDomElement effect = clip->getEffectAtIndex(ix); - QDomElement oldeffect = effect.cloneNode().toElement(); - effect.setAttribute(QStringLiteral("region"), region); - EditEffectCommand *command = new EditEffectCommand(this, clip->track(), clip->startPos(), oldeffect, effect, ix, true, true, true); - m_commandStack->push(command); -} - -void CustomTrackView::cutClip(const ItemInfo &info, const GenTime &cutTime, bool cut, const EffectsList &oldStack, bool execute) -{ - if (cut) { - // cut clip - ClipItem *item = getClipItemAtStart(info.startPos, info.track, info.endPos); - bool selectDup = false; - ItemInfo selectedInfo; - if ((m_dragItem != nullptr) && m_dragItem->type() == AVWidget) { - selectedInfo = m_dragItem->info(); - } - if (item == m_dragItem) { - clearSelection(); - selectDup = true; - } - if ((item == nullptr) || !info.contains(cutTime)) { - emit displayMessage(i18n("Cannot find clip to cut"), ErrorMessage); - return; - } - if (execute) { - if (!m_timeline->track(info.track)->cut(cutTime.seconds())) { - // Error cuting clip in playlist - qCDebug(KDENLIVE_LOG) << "/// ERROR CUTTING CLIP PLAYLIST!!"; - return; - } - } - if (!selectDup && info.track == selectedInfo.track && (selectedInfo.contains(info.startPos) || selectedInfo.contains(info.endPos))) { - clearSelection(); - } - delete item; - m_timeline->reloadTrack(info, false); - - // remove unwanted effects - // fade in from 2nd part of the clip - item = getClipItemAtStart(info.startPos, info.track, cutTime); - if (!item) { - qCDebug(KDENLIVE_LOG) << "* * * CANNOT FIND CUT SRC CLIP AT: " << info.startPos.frames(25); - } - ClipItem *dup = getClipItemAtStart(cutTime, info.track, info.endPos); - int ix = -1; - if (!dup) { - qCDebug(KDENLIVE_LOG) << "* * * CANNOT FIND CUT CLIP AT: " << cutTime.frames(25); - } else { - dup->binClip()->addRef(); - ix = dup->hasEffect(QString(), QStringLiteral("fadein")); - if (ix != -1) { - QDomElement oldeffect = dup->effectAtIndex(ix); - dup->deleteEffect(oldeffect.attribute(QStringLiteral("kdenlive_ix")).toInt()); - } - ix = dup->hasEffect(QString(), QStringLiteral("fade_from_black")); - if (ix != -1) { - QDomElement oldeffect = dup->effectAtIndex(ix); - dup->deleteEffect(oldeffect.attribute(QStringLiteral("kdenlive_ix")).toInt()); - } - } - if (item) { - // fade out from 1st part of the clip - ix = item->hasEffect(QString(), QStringLiteral("fadeout")); - if (ix != -1) { - QDomElement oldeffect = item->effectAtIndex(ix); - item->deleteEffect(oldeffect.attribute(QStringLiteral("kdenlive_ix")).toInt()); - } - ix = item->hasEffect(QString(), QStringLiteral("fade_to_black")); - if (ix != -1) { - QDomElement oldeffect = item->effectAtIndex(ix); - item->deleteEffect(oldeffect.attribute(QStringLiteral("kdenlive_ix")).toInt()); - } - - if (item->checkKeyFrames(m_document->width(), m_document->height(), (info.cropDuration + info.cropStart).frames(pCore->getCurrentFps()))) { - slotRefreshEffects(item); - } - } - if (dup) { - if (dup->checkKeyFrames(m_document->width(), m_document->height(), (info.cropDuration + info.cropStart).frames(pCore->getCurrentFps()), - (cutTime - info.startPos).frames(pCore->getCurrentFps()))) { - slotRefreshEffects(dup); - } - if (selectDup) { - dup->setSelected(true); - dup->setMainSelectedClip(true); - m_dragItem = dup; - emit clipItemSelected(dup); - } else if (selectedInfo.isValid() && m_dragItem == nullptr) { - m_dragItem = getClipItemAtStart(selectedInfo.startPos, selectedInfo.track); - if (m_dragItem) { - m_dragItem->setSelected(true); - m_dragItem->setMainSelectedClip(true); - emit clipItemSelected(static_cast(m_dragItem)); - } - } - } - return; - } - // uncut clip - ClipItem *item = getClipItemAtStart(info.startPos, info.track); - ClipItem *dup = getClipItemAtStart(cutTime, info.track); - bool selectDup = false; - if (m_dragItem == item || m_dragItem == dup) { - emit clipItemSelected(nullptr); - selectDup = true; - } - if ((item == nullptr) || (dup == nullptr) || item == dup) { - emit displayMessage(i18n("Cannot find clip to uncut"), ErrorMessage); - return; - } - if (!m_timeline->track(info.track)->del(cutTime.seconds())) { - emit displayMessage(i18n("Error removing clip at %1 on track %2", m_document->timecode().getTimecodeFromFrames(cutTime.frames(pCore->getCurrentFps())), - m_timeline->getTrackInfo(info.track).trackName), - ErrorMessage); - return; - } - dup->binClip()->removeRef(); - m_timeline->track(info.track)->resize(info.startPos.seconds(), (info.endPos - cutTime).seconds(), true); - m_timeline->reloadTrack(info.track, info.startPos.frames(pCore->getCurrentFps()), info.endPos.frames(pCore->getCurrentFps())); - item = getClipItemAtStart(info.startPos, info.track); - // Restore original effects - item->setEffectList(oldStack); - if (selectDup) { - item->setSelected(true); - item->setMainSelectedClip(true); - m_dragItem = item; - emit clipItemSelected(item); - } -} - -Transition *CustomTrackView::cutTransition(const ItemInfo &info, const GenTime &cutTime, bool cut, const QDomElement &oldStack, bool execute) -{ - if (cut) { - // cut clip - Transition *item = getTransitionItemAtStart(info.startPos, info.track); - if ((item == nullptr) || cutTime >= item->endPos() || cutTime <= item->startPos()) { - emit displayMessage(i18n("Cannot find transition to cut"), ErrorMessage); - if (item) { - qCDebug(KDENLIVE_LOG) << "///////// ERROR CUTTING transition : (" << item->startPos().frames(25) << '-' << item->endPos().frames(25) - << "), INFO: (" << info.startPos.frames(25) << '-' << info.endPos.frames(25) << ')' << ", CUT: " << cutTime.frames(25); - } else { - qCDebug(KDENLIVE_LOG) << "/// ERROR NO transition at: " << info.startPos.frames(pCore->getCurrentFps()) << ", track: " << info.track; - } - return nullptr; - } - - bool success = true; - if (execute) { - success = m_timeline->transitionHandler->moveTransition(item->transitionTag(), info.track, info.track, item->transitionEndTrack(), info.startPos, - info.endPos, info.startPos, cutTime); - if (success) { - success = m_timeline->transitionHandler->addTransition(item->transitionTag(), item->transitionEndTrack(), info.track, cutTime, info.endPos, - item->toXML()); - } - } - int cutPos = (int)cutTime.frames(pCore->getCurrentFps()); - ItemInfo newPos; - newPos.startPos = cutTime; - newPos.endPos = info.endPos; - newPos.cropStart = item->info().cropStart + (cutTime - info.startPos); - newPos.track = info.track; - newPos.cropDuration = newPos.endPos - newPos.startPos; - - bool snap = KdenliveSettings::snaptopoints(); - KdenliveSettings::setSnaptopoints(false); - Transition *dup = item->clone(newPos); - connect(dup, &AbstractClipItem::selectItem, this, &CustomTrackView::slotSelectItem); - dup->setPos(newPos.startPos.frames(pCore->getCurrentFps()), getPositionFromTrack(newPos.track) + 1 + dup->itemOffset()); - - item->resizeEnd(cutPos); - scene()->addItem(dup); - - if (item->checkKeyFrames(m_document->width(), m_document->height(), (info.cropDuration + info.cropStart).frames(pCore->getCurrentFps()))) { - m_timeline->transitionHandler->updateTransitionParams(item->transitionTag(), item->transitionEndTrack(), info.track, info.startPos, cutTime, - item->toXML()); - } - if (dup->checkKeyFrames(m_document->width(), m_document->height(), (info.cropDuration + info.cropStart).frames(pCore->getCurrentFps()), - (cutTime - item->startPos()).frames(pCore->getCurrentFps()))) { - m_timeline->transitionHandler->updateTransitionParams(item->transitionTag(), item->transitionEndTrack(), info.track, cutTime, info.endPos, - dup->toXML()); - } - - KdenliveSettings::setSnaptopoints(snap); - return dup; - } - // uncut transition - Transition *item = getTransitionItemAtStart(info.startPos, info.track); - Transition *dup = getTransitionItemAtStart(cutTime, info.track); - - if ((item == nullptr) || (dup == nullptr) || item == dup) { - emit displayMessage(i18n("Cannot find transition to uncut"), ErrorMessage); - return nullptr; - } - - ItemInfo transitionInfo = dup->info(); - if (!m_timeline->transitionHandler->deleteTransition(dup->transitionTag(), dup->transitionEndTrack(), transitionInfo.track, cutTime, transitionInfo.endPos, - dup->toXML(), false)) { - emit displayMessage(i18n("Error removing transition at %1 on track %2", - m_document->timecode().getTimecodeFromFrames(cutTime.frames(pCore->getCurrentFps())), - m_timeline->getTrackInfo(info.track).trackName), - ErrorMessage); - return nullptr; - } - bool snap = KdenliveSettings::snaptopoints(); - KdenliveSettings::setSnaptopoints(false); - - if (dup->isSelected() && dup == m_dragItem) { - item->setSelected(true); - item->setMainSelectedClip(true); - m_dragItem = item; - emit transitionItemSelected(item); - } - scene()->removeItem(dup); - delete dup; - dup = nullptr; - - ItemInfo clipinfo = item->info(); - bool success = m_timeline->transitionHandler->moveTransition(item->transitionTag(), clipinfo.track, clipinfo.track, item->transitionEndTrack(), - clipinfo.startPos, clipinfo.endPos, clipinfo.startPos, transitionInfo.endPos); - - if (success) { - item->resizeEnd((int)info.endPos.frames(pCore->getCurrentFps())); - item->setTransitionParameters(oldStack); - m_timeline->transitionHandler->updateTransitionParams(item->transitionTag(), item->transitionEndTrack(), info.track, info.startPos, info.endPos, - oldStack); - } else { - emit displayMessage(i18n("Error when resizing clip"), ErrorMessage); - } - KdenliveSettings::setSnaptopoints(snap); - return item; -} - -void CustomTrackView::slotAddTransitionToSelectedClips(const QDomElement &transition, QList itemList) -{ - if (itemList.isEmpty()) { - itemList = scene()->selectedItems(); - } - if (itemList.count() == 1) { - if (itemList.at(0)->type() == AVWidget) { - ClipItem *item = static_cast(itemList.at(0)); - ItemInfo info; - info.track = item->track(); - ClipItem *transitionClip = nullptr; - const int transitiontrack = getPreviousVideoTrack(info.track); - GenTime pos = GenTime((int)(mapToScene(m_menuPosition).x()), pCore->getCurrentFps()); - if (pos < item->startPos() + item->cropDuration() / 2) { - // add transition to clip start - info.startPos = item->startPos(); - if (transitiontrack != 0) { - transitionClip = getClipItemAtMiddlePoint(info.startPos.frames(pCore->getCurrentFps()), transitiontrack); - } - if ((transitionClip != nullptr) && transitionClip->endPos() < item->endPos()) { - info.endPos = transitionClip->endPos(); - } else { - info.endPos = info.startPos + GenTime(m_document->getFramePos(KdenliveSettings::transition_duration()), pCore->getCurrentFps()); - } - // Check there is no other transition at that place - double startY = getPositionFromTrack(info.track) + 1 + m_tracksHeight / 2; - QRectF r(info.startPos.frames(pCore->getCurrentFps()), startY, (info.endPos - info.startPos).frames(pCore->getCurrentFps()), - m_tracksHeight / 2); - QList selection = m_scene->items(r); - bool transitionAccepted = true; - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == TransitionWidget) { - Transition *tr = static_cast(selection.at(i)); - if (tr->startPos() - info.startPos > GenTime(5, pCore->getCurrentFps())) { - if (tr->startPos() < info.endPos) { - info.endPos = tr->startPos(); - } - } else { - transitionAccepted = false; - } - } - } - if (transitionAccepted) { - slotAddTransition(item, info, transitiontrack, transition); - } else { - emit displayMessage(i18n("Cannot add transition"), ErrorMessage); - } - - } else { - // add transition to clip end - info.endPos = item->endPos(); - if (transitiontrack != 0) { - transitionClip = getClipItemAtMiddlePoint(info.endPos.frames(pCore->getCurrentFps()), transitiontrack); - } - if ((transitionClip != nullptr) && transitionClip->startPos() > item->startPos()) { - info.startPos = transitionClip->startPos(); - } else { - GenTime duration(m_document->getFramePos(KdenliveSettings::transition_duration()), pCore->getCurrentFps()); - if (info.endPos < duration) { - info.startPos = GenTime(); - } else { - info.startPos = info.endPos - duration; - } - } - if (transition.attribute(QStringLiteral("tag")) == QLatin1String("luma")) { - EffectsList::setParameter(transition, QStringLiteral("reverse"), QStringLiteral("1")); - } else if (transition.attribute(QStringLiteral("id")) == QLatin1String("slide")) { - EffectsList::setParameter(transition, QStringLiteral("invert"), QStringLiteral("1")); - } - - // Check there is no other transition at that place - double startY = getPositionFromTrack(info.track) + 1 + m_tracksHeight / 2; - QRectF r(info.startPos.frames(pCore->getCurrentFps()), startY, (info.endPos - info.startPos).frames(pCore->getCurrentFps()), - m_tracksHeight / 2); - QList selection = m_scene->items(r); - bool transitionAccepted = true; - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == TransitionWidget) { - Transition *tr = static_cast(selection.at(i)); - if (info.endPos - tr->endPos() > GenTime(5, pCore->getCurrentFps())) { - if (tr->endPos() > info.startPos) { - info.startPos = tr->endPos(); - } - } else { - transitionAccepted = false; - } - } - } - if (transitionAccepted) { - slotAddTransition(item, info, transitiontrack, transition); - } else { - emit displayMessage(i18n("Cannot add transition"), ErrorMessage); - } - } - } - } else - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget) { - ClipItem *item = static_cast(itemList.at(i)); - ItemInfo info; - info.startPos = item->startPos(); - info.endPos = info.startPos + GenTime(m_document->getFramePos(KdenliveSettings::transition_duration()), pCore->getCurrentFps()); - info.track = item->track(); - - // Check there is no other transition at that place - double startY = getPositionFromTrack(info.track) + 1 + m_tracksHeight / 2; - QRectF r(info.startPos.frames(pCore->getCurrentFps()), startY, (info.endPos - info.startPos).frames(pCore->getCurrentFps()), - m_tracksHeight / 2); - QList selection = m_scene->items(r); - bool transitionAccepted = true; - for (int j = 0; j < selection.count(); ++j) { - if (selection.at(j)->type() == TransitionWidget) { - Transition *tr = static_cast(selection.at(j)); - if (tr->startPos() - info.startPos > GenTime(5, pCore->getCurrentFps())) { - if (tr->startPos() < info.endPos) { - info.endPos = tr->startPos(); - } - } else { - transitionAccepted = false; - } - } - } - int transitiontrack = getPreviousVideoTrack(info.track); - if (transitionAccepted) { - slotAddTransition(item, info, transitiontrack, transition); - } else { - emit displayMessage(i18n("Cannot add transition"), ErrorMessage); - } - } - } -} - -void CustomTrackView::slotAddTransition(ClipItem * /*clip*/, const ItemInfo &transitionInfo, int endTrack, const QDomElement &transition) -{ - if (transitionInfo.startPos >= transitionInfo.endPos) { - emit displayMessage(i18n("Invalid transition"), ErrorMessage); - return; - } - auto *command = new AddTransitionCommand(this, transitionInfo, endTrack, transition, false, true); - m_commandStack->push(command); -} - -void CustomTrackView::addTransition(const ItemInfo &transitionInfo, int endTrack, const QDomElement ¶ms, bool refresh) -{ - // If transition is to be created from paste, then use that automatic setting. - // Otherwise, when no automatic setting is present, use the current configuration setting. - bool autotrans = params.attribute(QStringLiteral("automatic"), KdenliveSettings::automatictransitions() ? QStringLiteral("1") : QStringLiteral("0")) == - QStringLiteral("1"); - auto *tr = new Transition(transitionInfo, endTrack, pCore->getCurrentFps(), params, autotrans); - connect(tr, &AbstractClipItem::selectItem, this, &CustomTrackView::slotSelectItem); - tr->setPos(transitionInfo.startPos.frames(pCore->getCurrentFps()), getPositionFromTrack(transitionInfo.track) + tr->itemOffset() + 1); - ////qCDebug(KDENLIVE_LOG) << "---- ADDING transition " << params.attribute("value"); - if (m_timeline->transitionHandler->addTransition(tr->transitionTag(), endTrack, transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, - tr->toXML())) { - scene()->addItem(tr); - if (refresh) { - monitorRefresh(transitionInfo, true); - } - } else { - emit displayMessage(i18n("Cannot add transition"), ErrorMessage); - delete tr; - } -} - -void CustomTrackView::deleteTransition(const ItemInfo &transitionInfo, int endTrack, const QDomElement & /*params*/, bool refresh) -{ - Transition *item = getTransitionItemAt(transitionInfo.startPos, transitionInfo.track); - if (!item) { - // TODO: rename to "Select transition to delete - emit displayMessage(i18n("Select clip to delete"), ErrorMessage); - return; - } - m_timeline->transitionHandler->deleteTransition(item->transitionTag(), endTrack, transitionInfo.track, transitionInfo.startPos, transitionInfo.endPos, - item->toXML(), refresh); - if (m_dragItem == item) { - m_dragItem->setMainSelectedClip(false); - m_dragItem = nullptr; - } - if (refresh) { - monitorRefresh(transitionInfo, true); - } - // animate item deletion - item->closeAnimation(); - emit transitionItemSelected(nullptr); -} - -void CustomTrackView::slotTransitionUpdated(Transition *tr, const QDomElement &old) -{ - ////qCDebug(KDENLIVE_LOG) << "TRANS UPDATE, TRACKS: " << old.attribute("transition_btrack") << ", NEW: " << tr->toXML().attribute("transition_btrack"); - QDomElement xml = tr->toXML(); - if (old.isNull() || xml.isNull()) { - emit displayMessage(i18n("Cannot update transition"), ErrorMessage); - return; - } - EditTransitionCommand *command = new EditTransitionCommand(this, tr->track(), tr->startPos(), old, xml, false); - updateTrackDuration(tr->track(), command); - m_commandStack->push(command); -} - -void CustomTrackView::updateTransition(int track, const GenTime &pos, const QDomElement &oldTransition, const QDomElement &transition, - bool updateTransitionWidget) -{ - Transition *item = getTransitionItemAt(pos, track); - if (!item) { - qCWarning(KDENLIVE_LOG) << "Unable to find transition at pos :" << pos.frames(pCore->getCurrentFps()) << ", ON track: " << track; - return; - } - - bool force = false; - if (oldTransition.attribute(QStringLiteral("transition_atrack")) != transition.attribute(QStringLiteral("transition_atrack")) || - oldTransition.attribute(QStringLiteral("transition_btrack")) != transition.attribute(QStringLiteral("transition_btrack"))) { - force = true; - } - m_timeline->transitionHandler->updateTransition(oldTransition.attribute(QStringLiteral("tag")), transition.attribute(QStringLiteral("tag")), - transition.attribute(QStringLiteral("transition_btrack")).toInt(), - transition.attribute(QStringLiteral("transition_atrack")).toInt(), item->startPos(), item->endPos(), - transition, force); - ////qCDebug(KDENLIVE_LOG) << "ORIGINAL TRACK: "<< oldTransition.attribute("transition_btrack") << ", NEW TRACK: - ///"<setTransitionParameters(transition); - if (updateTransitionWidget && item->isSelected()) { - ItemInfo info = item->info(); - QPoint p; - ClipItem *transitionClip = getClipItemAtStart(info.startPos, info.track); - if ((transitionClip != nullptr) && (transitionClip->binClip() != nullptr)) { - int frameWidth = transitionClip->binClip()->getProducerIntProperty(QStringLiteral("meta.media.width")); - int frameHeight = transitionClip->binClip()->getProducerIntProperty(QStringLiteral("meta.media.height")); - double factor = transitionClip->binClip()->getProducerProperty(QStringLiteral("aspect_ratio")).toDouble(); - if (factor == 0) { - factor = 1.0; - } - p.setX((int)(frameWidth * factor + 0.5)); - p.setY(frameHeight); - } - emit transitionItemSelected(item, getPreviousVideoTrack(info.track), p, true); - } - monitorRefresh(item->info(), true); -} - -void CustomTrackView::dragMoveEvent(QDragMoveEvent *event) -{ - if (m_clipDrag) { - const QPointF pos = mapToScene(event->pos()); - if (m_selectionGroup) { - m_selectionGroup->setPos(pos); - emit mousePosition((int)(m_selectionGroup->scenePos().x() + 0.5)); - event->acceptProposedAction(); - } else if (m_dragItem) { - m_dragItem->setPos(pos); - emit mousePosition((int)(m_dragItem->scenePos().x() + 0.5)); - event->acceptProposedAction(); - } else { - // Drag enter was not possible, try again at mouse position - insertDropClips(event->mimeData(), event->pos()); - event->accept(); - } - } else { - QGraphicsView::dragMoveEvent(event); - } -} - -void CustomTrackView::dragLeaveEvent(QDragLeaveEvent *event) -{ - if (((m_selectionGroup != nullptr) || (m_dragItem != nullptr)) && m_clipDrag) { - QList items; - QMutexLocker lock(&m_selectionMutex); - if (m_selectionGroup) { - items = m_selectionGroup->childItems(); - } else if (m_dragItem) { - m_dragItem->setMainSelectedClip(false); - items.append(m_dragItem); - } - qDeleteAll(items); - if (m_selectionGroup) { - scene()->destroyItemGroup(m_selectionGroup); - } - m_selectionGroup = nullptr; - m_dragItem = nullptr; - event->accept(); - } else { - QGraphicsView::dragLeaveEvent(event); - } -} - -void CustomTrackView::enterEvent(QEvent *event) -{ - m_currentToolManager->enterEvent(0, m_tracksHeight * m_scene->scale().y()); - QGraphicsView::enterEvent(event); -} - -void CustomTrackView::leaveEvent(QEvent *event) -{ - removeTipAnimation(); - m_currentToolManager->leaveEvent(); - QGraphicsView::leaveEvent(event); -} - -void CustomTrackView::dropEvent(QDropEvent *event) -{ - GenTime startPos; - GenTime duration; - if (((m_selectionGroup != nullptr) || (m_dragItem != nullptr)) && m_clipDrag) { - QList items; - if (m_selectionGroup) { - items = m_selectionGroup->childItems(); - startPos = GenTime((int)m_selectionGroup->scenePos().x(), pCore->getCurrentFps()); - duration = m_selectionGroup->duration(); - } else if (m_dragItem) { - m_dragItem->setMainSelectedClip(false); - startPos = m_dragItem->startPos(); - duration = m_dragItem->cropDuration(); - items.append(m_dragItem); - } - resetSelectionGroup(); - m_dragItem = nullptr; - m_scene->clearSelection(); - auto *addCommand = new QUndoCommand(); - addCommand->setText(i18n("Add timeline clip")); - QList brokenClips; - - // Add refresh command for undo - RefreshMonitorCommand *firstRefresh = new RefreshMonitorCommand(this, ItemInfo(), false, true, addCommand); - for (int i = 0; i < items.count(); ++i) { - m_scene->removeItem(items.at(i)); - } - QList range; - if (m_scene->editMode() == TimelineMode::InsertEdit) { - cutTimeline(startPos.frames(pCore->getCurrentFps()), QList(), QList(), addCommand); - ItemInfo info; - info.startPos = startPos; - info.cropDuration = duration; - new AddSpaceCommand(this, info, QList(), true, addCommand); - } else if (m_scene->editMode() == TimelineMode::OverwriteEdit) { - // Should we really overwrite all unlocked tracks ? If not we need to calculate the track for audio split first - extractZone(QPoint(startPos.frames(pCore->getCurrentFps()), (startPos + duration).frames(pCore->getCurrentFps())), false, QList(), - addCommand); - /*for (int i = 0; i < items.count(); ++i) { - if (items.at(i)->type() != AVWidget) - continue; - ItemInfo info = items.at(i)->info(); - extractZone(QPoint(info.startPos.frames(pCore->getCurrentFps()), (info.startPos+info.cropDuration).frames(pCore->getCurrentFps())), false, - QList(), addCommand, info.track); - }*/ - } - ItemInfo info; - for (int i = 0; i < items.count(); ++i) { - if (items.at(i)->type() != AVWidget) { - continue; - } - ClipItem *item = static_cast(items.at(i)); - ClipType cType = item->clipType(); - if (items.count() == 1) { - updateClipTypeActions(item); - } else { - updateClipTypeActions(nullptr); - } - info = item->info(); - QString clipBinId = item->getBinId(); - PlaylistState::ClipState pState = item->clipState(); - if (item->hasVisibleVideo()) { - range << info; - } - if (KdenliveSettings::splitaudio()) { - if (m_timeline->getTrackInfo(info.track).type == AudioTrack) { - if (cType != Audio) { - pState = PlaylistState::AudioOnly; - } - } else if (item->isSplittable()) { - pState = PlaylistState::VideoOnly; - } - } - new AddTimelineClipCommand(this, clipBinId, info, item->effectList(), pState, true, false, false, addCommand); - // Automatic audio split - if (KdenliveSettings::splitaudio() && item->isSplittable() && pState != PlaylistState::AudioOnly) { - splitAudio(false, info, m_timeline->audioTarget, addCommand); - } else { - updateTrackDuration(info.track, addCommand); - } - - // Disabled since we now have working track compositing - /*if (item->binClip()->isTransparent() && getTransitionItemAtStart(info.startPos, info.track) == nullptr) { - // add transparency transition if space is available - if (canBePastedTo(info, TransitionWidget)) { - QDomElement trans = MainWindow::transitions.getEffectByTag(QStringLiteral("affine"), QString()).cloneNode().toElement(); - new AddTransitionCommand(this, info, getPreviousVideoTrack(info.track), trans, false, true, addCommand); - } - }*/ - } - qDeleteAll(items); - // Add refresh command for redo - firstRefresh->updateRange(range); - new RefreshMonitorCommand(this, range, true, false, addCommand); - if (addCommand->childCount() > 0) { - m_commandStack->push(addCommand); - } else { - delete addCommand; - } - /* - m_pasteEffectsAction->setEnabled(m_copiedItems.count() == 1);*/ - event->setDropAction(Qt::MoveAction); - event->accept(); - ClipItem *clp = getClipItemAtStart(info.startPos, info.track); - if (clp) { - slotSelectItem(clp); - } - - /// \todo enable when really working - // alignAudio(); - - } else { - QGraphicsView::dropEvent(event); - } - setFocus(); -} - -void CustomTrackView::cutTimeline(int cutPos, const QList &excludedClips, const QList &excludedTransitions, QUndoCommand *masterCommand, - int track) -{ - QRectF rect; - if (track == -1) { - // Cut all tracks - rect = QRectF(cutPos, 0, 1, m_timeline->visibleTracksCount() * m_tracksHeight); - } else { - // Cut only selected track - rect = QRectF(cutPos, getPositionFromTrack(track) + m_tracksHeight / 2, 1, 2); - } - QList selection = m_scene->items(rect); - // We are going to move clips that are after zone, so break locked groups first. - QList clipsToCut; - QList transitionsToCut; - for (int i = 0; i < selection.count(); ++i) { - AbstractClipItem *item = static_cast(selection.at(i)); - if ((item == nullptr) || !item->isEnabled() || (item->parentItem() == nullptr)) { - continue; - } - ItemInfo moveInfo = item->info(); - // Skip locked tracks - if (m_timeline->getTrackInfo(moveInfo.track).isLocked) { - continue; - } - if (item->type() == AVWidget) { - if (excludedClips.contains(moveInfo)) { - continue; - } - clipsToCut.append(moveInfo); - } else if (item->type() == TransitionWidget) { - if (excludedTransitions.contains(moveInfo)) { - continue; - } - transitionsToCut.append(moveInfo); - } - } - if (!clipsToCut.isEmpty() || !transitionsToCut.isEmpty()) { - breakLockedGroups(clipsToCut, transitionsToCut, masterCommand); - } - // Razor - GenTime cutPosition = GenTime(cutPos, pCore->getCurrentFps()); - for (int i = 0; i < selection.count(); ++i) { - if (!selection.at(i)->isEnabled()) { - continue; - } - if (selection.at(i)->type() == AVWidget) { - ClipItem *clip = static_cast(selection.at(i)); - // Skip locked tracks - if (m_timeline->getTrackInfo(clip->track()).isLocked) { - continue; - } - ItemInfo info = clip->info(); - if (excludedClips.contains(info) || cutPosition == info.startPos) { - continue; - } - new RazorClipCommand(this, info, clip->effectList(), cutPosition, true, masterCommand); - } else if (selection.at(i)->type() == TransitionWidget) { - Transition *trans = static_cast(selection.at(i)); - // Skip locked tracks - if (m_timeline->getTrackInfo(trans->track()).isLocked) { - continue; - } - ItemInfo info = trans->info(); - if (excludedTransitions.contains(info) || cutPosition == info.startPos) { - continue; - } - new RazorTransitionCommand(this, info, trans->toXML(), cutPosition, true, masterCommand); - } - } -} - -void CustomTrackView::extractZone(QPoint z, bool closeGap, const QList &excludedClips, QUndoCommand *masterCommand, int track) -{ - // remove track zone and close gap - if (closeGap && m_timeline->getTrackInfo(m_selectedTrack).isLocked) { - // Cannot perform an Extract operation on a locked track - emit displayMessage(i18n("Cannot perform operation on a locked track"), ErrorMessage); - return; - } - if (z.isNull()) { - z = m_document->zone(); - z.setY(z.y() + 1); - } - QRectF rect; - if (track == -1) { - // All tracks - rect = QRectF(z.x(), 0, z.y() - z.x() - 1, m_timeline->visibleTracksCount() * m_tracksHeight); - } else { - // one track only - rect = QRectF(z.x(), getPositionFromTrack(track) + m_tracksHeight / 2, z.y() - z.x() - 1, 2); - } - QList selection = m_scene->items(rect); - QList gapSelection; - if (selection.isEmpty()) { - return; - } - GenTime inPoint(z.x(), pCore->getCurrentFps()); - GenTime outPoint(z.y(), pCore->getCurrentFps()); - bool hasMasterCommand = masterCommand != nullptr; - if (!hasMasterCommand) { - masterCommand = new QUndoCommand(); - masterCommand->setText(i18n("Remove Zone")); - } - - if (closeGap) { - // We are going to move clips that are after zone, so break locked groups first. - QRectF gapRect = QRectF(z.x(), 0, sceneRect().width() - z.x(), m_timeline->visibleTracksCount() * m_tracksHeight); - gapSelection = m_scene->items(gapRect); - QList clipsToMove; - QList transitionsToMove; - for (int i = 0; i < gapSelection.count(); ++i) { - if (!gapSelection.at(i)->isEnabled()) { - continue; - } - if (gapSelection.at(i)->type() == AVWidget) { - ClipItem *clip = static_cast(gapSelection.at(i)); - // Skip locked tracks - if (m_timeline->getTrackInfo(clip->track()).isLocked) { - continue; - } - ItemInfo moveInfo = clip->info(); - if (clip->type() == AVWidget) { - clipsToMove.append(moveInfo); - } else if (clip->type() == TransitionWidget) { - transitionsToMove.append(moveInfo); - } - } - } - if (!clipsToMove.isEmpty() || !transitionsToMove.isEmpty()) { - breakLockedGroups(clipsToMove, transitionsToMove, masterCommand); - } - } - QList range; - RefreshMonitorCommand *firstRefresh = new RefreshMonitorCommand(this, ItemInfo(), false, true, masterCommand); - for (int i = 0; i < selection.count(); ++i) { - if (!selection.at(i)->isEnabled()) { - continue; - } - if (selection.at(i)->type() == AVWidget) { - ClipItem *clip = static_cast(selection.at(i)); - // Skip locked tracks - if (m_timeline->getTrackInfo(clip->track()).isLocked) { - continue; - } - ItemInfo baseInfo = clip->info(); - if (excludedClips.contains(baseInfo)) { - continue; - } - bool refresh = clip->hasVisibleVideo(); - if (clip->startPos() < inPoint) { - ItemInfo info = baseInfo; - info.startPos = inPoint; - info.cropDuration = info.endPos - info.startPos; - if (clip->endPos() > outPoint) { - new RazorClipCommand(this, baseInfo, clip->effectList(), outPoint, true, masterCommand); - info.cropDuration = outPoint - inPoint; - info.endPos = outPoint; - baseInfo.endPos = outPoint; - baseInfo.cropDuration = outPoint - baseInfo.startPos; - } - new RazorClipCommand(this, baseInfo, clip->effectList(), inPoint, true, masterCommand); - if (refresh) { - range << info; - } - new AddTimelineClipCommand(this, clip->getBinId(), info, clip->effectList(), clip->clipState(), true, true, false, masterCommand); - } else if (clip->endPos() > outPoint) { - new RazorClipCommand(this, baseInfo, clip->effectList(), outPoint, true, masterCommand); - ItemInfo newInfo = baseInfo; - newInfo.endPos = outPoint; - newInfo.cropDuration = newInfo.endPos - newInfo.startPos; - if (refresh) { - range << newInfo; - } - new AddTimelineClipCommand(this, clip->getBinId(), newInfo, clip->effectList(), clip->clipState(), true, true, false, masterCommand); - } else { - // Clip is entirely inside zone, delete it - if (refresh) { - range << baseInfo; - } - new AddTimelineClipCommand(this, clip->getBinId(), baseInfo, clip->effectList(), clip->clipState(), true, true, false, masterCommand); - } - } else if (selection.at(i)->type() == TransitionWidget) { - Transition *trans = static_cast(selection.at(i)); - // Skip locked tracks - if (m_timeline->getTrackInfo(trans->track()).isLocked) { - continue; - } - ItemInfo baseInfo = trans->info(); - if (excludedClips.contains(baseInfo)) { - continue; - } - QDomElement xml = trans->toXML(); - if (trans->startPos() < inPoint) { - ItemInfo info = baseInfo; - ItemInfo newInfo = baseInfo; - info.startPos = inPoint; - info.cropDuration = info.endPos - info.startPos; - if (trans->endPos() > outPoint) { - // Transition starts before and ends after zone, proceed cuts - new RazorTransitionCommand(this, baseInfo, xml, outPoint, true, masterCommand); - info.cropDuration = outPoint - inPoint; - info.endPos = outPoint; - newInfo.endPos = outPoint; - newInfo.cropDuration = outPoint - newInfo.startPos; - } - new RazorTransitionCommand(this, newInfo, xml, inPoint, true, masterCommand); - new AddTransitionCommand(this, info, trans->transitionEndTrack(), xml, true, true, masterCommand); - } else if (trans->endPos() > outPoint) { - // Cut and remove first part - new RazorTransitionCommand(this, baseInfo, xml, outPoint, true, masterCommand); - ItemInfo info = baseInfo; - info.endPos = outPoint; - info.cropDuration = info.endPos - info.startPos; - new AddTransitionCommand(this, info, trans->transitionEndTrack(), xml, true, true, masterCommand); - } else { - // Transition is entirely inside zone, delete it - new AddTransitionCommand(this, baseInfo, trans->transitionEndTrack(), xml, true, true, masterCommand); - } - } - } - if (closeGap) { - // Remove empty zone - QList clipsToMove; - QList transitionsToMove; - for (int i = 0; i < gapSelection.count(); ++i) { - if (gapSelection.at(i)->type() == AVWidget || gapSelection.at(i)->type() == TransitionWidget) { - AbstractClipItem *item = static_cast(gapSelection.at(i)); - if (m_timeline->getTrackInfo(item->track()).isLocked) { - continue; - } - ItemInfo moveInfo = item->info(); - if (item->type() == AVWidget) { - if (moveInfo.startPos < outPoint) { - if (moveInfo.endPos <= outPoint) { - continue; - } - moveInfo.startPos = outPoint; - moveInfo.cropDuration = moveInfo.endPos - moveInfo.startPos; - } - clipsToMove.append(moveInfo); - } else if (item->type() == TransitionWidget) { - if (moveInfo.startPos < outPoint) { - if (moveInfo.endPos <= outPoint) { - continue; - } - moveInfo.startPos = outPoint; - moveInfo.cropDuration = moveInfo.endPos - moveInfo.startPos; - } - transitionsToMove.append(moveInfo); - } - } - } - if (!clipsToMove.isEmpty() || !transitionsToMove.isEmpty()) { - new InsertSpaceCommand(this, clipsToMove, transitionsToMove, -1, -(outPoint - inPoint), true, masterCommand); - updateTrackDuration(-1, masterCommand); - } - } - // Add refresh command for redo - firstRefresh->updateRange(range); - new RefreshMonitorCommand(this, range, true, false, masterCommand); - if (!hasMasterCommand) { - m_commandStack->push(masterCommand); - } - return; -} - -void CustomTrackView::adjustTimelineTransitions(TimelineMode::EditMode mode, Transition *item, QUndoCommand *command) -{ - if (mode == TimelineMode::OverwriteEdit) { - // if we are in overwrite or push mode, move clips accordingly - bool snap = KdenliveSettings::snaptopoints(); - KdenliveSettings::setSnaptopoints(false); - ItemInfo info = item->info(); - QRectF rect(info.startPos.frames(pCore->getCurrentFps()), getPositionFromTrack(info.track) + m_tracksHeight, - (info.endPos - info.startPos).frames(pCore->getCurrentFps()) - 1, 5); - QList selection = m_scene->items(rect); - selection.removeAll(item); - for (int i = 0; i < selection.count(); ++i) { - if (!selection.at(i)->isEnabled()) { - continue; - } - if (selection.at(i)->type() == TransitionWidget) { - Transition *tr = static_cast(selection.at(i)); - if (tr->startPos() < info.startPos) { - ItemInfo firstPos = tr->info(); - ItemInfo newPos = firstPos; - firstPos.endPos = item->startPos(); - newPos.startPos = item->endPos(); - new MoveTransitionCommand(this, tr->info(), firstPos, true, false, command); - if (tr->endPos() > info.endPos) { - // clone transition - new AddTransitionCommand(this, newPos, tr->transitionEndTrack(), tr->toXML(), false, true, command); - } - } else if (tr->endPos() > info.endPos) { - // just resize - ItemInfo firstPos = tr->info(); - firstPos.startPos = item->endPos(); - new MoveTransitionCommand(this, tr->info(), firstPos, true, false, command); - } else { - // remove transition - new AddTransitionCommand(this, tr->info(), tr->transitionEndTrack(), tr->toXML(), true, true, command); - } - } - } - KdenliveSettings::setSnaptopoints(snap); - } -} - -QStringList CustomTrackView::mimeTypes() const -{ - QStringList qstrList; - // list of accepted MIME types for drop - qstrList.append(QStringLiteral("text/plain")); - qstrList.append(QStringLiteral("kdenlive/producerslist")); - qstrList.append(QStringLiteral("kdenlive/clip")); - return qstrList; -} - -Qt::DropActions CustomTrackView::supportedDropActions() const -{ - // returns what actions are supported when dropping - return Qt::MoveAction; -} - -void CustomTrackView::setDuration(int duration) -{ - if (m_projectDuration == duration) { - return; - } - int diff = qAbs(duration - sceneRect().width()); - if (diff * matrix().m11() > -50) { - if (matrix().m11() < 0.4) { - setSceneRect(0, 0, (duration + 100 / matrix().m11()), sceneRect().height()); - } else { - setSceneRect(0, 0, (duration + 300), sceneRect().height()); - } - } - m_projectDuration = duration; -} - -int CustomTrackView::duration() const -{ - return m_projectDuration; -} - -void CustomTrackView::addTrack(const TrackInfo &type, int ix) -{ - clearSelection(); - emit transitionItemSelected(nullptr); - QList transitionInfos; - if (ix == -1 || ix > m_timeline->tracksCount()) { - ix = m_timeline->tracksCount() + 1; - } - if (ix <= m_timeline->videoTarget) { - m_timeline->videoTarget++; - } - if (ix <= m_timeline->audioTarget) { - m_timeline->audioTarget++; - } - // insert track in MLT's playlist - transitionInfos = m_document->renderer()->mltInsertTrack(ix, type.trackName, type.type == VideoTrack); - Mlt::Tractor *tractor = m_document->renderer()->lockService(); - m_document->renderer()->unlockService(tractor); - // Reload timeline and m_tracks structure from MLT's playlist - reloadTimeline(); - // Refresh track compositing and audio mix - m_timeline->refreshTransitions(); -} - -void CustomTrackView::reloadTimeline() -{ - removeTipAnimation(); - m_document->clipManager()->resetGroups(); - emit clipItemSelected(nullptr); - emit transitionItemSelected(nullptr); - QList selection = m_scene->items(); - selection.removeAll(m_cursorLine); - for (int i = 0; i < m_guides.count(); ++i) { - selection.removeAll(m_guides.at(i)); - } - qDeleteAll<>(selection); - m_timeline->getTracks(); - m_timeline->getTransitions(); - int maxHeight = m_tracksHeight * m_timeline->visibleTracksCount() * matrix().m22(); - for (int i = 0; i < m_guides.count(); ++i) { - m_guides.at(i)->setLine(0, 0, 0, maxHeight - 1); - } - if ((m_cursorLine->flags() & static_cast((QGraphicsItem::ItemIgnoresTransformations) != 0)) != 0) { - m_cursorLine->setLine(0, 0, 0, maxHeight - 1); - } else { - m_cursorLine->setLine(0, 0, 0, m_tracksHeight * m_timeline->visibleTracksCount() - 1); - } - viewport()->update(); -} - -void CustomTrackView::removeTrack(int ix) -{ - // Clear effect stack - clearSelection(); - emit transitionItemSelected(nullptr); - // Make sure the selected track index is not outside range - m_selectedTrack = qBound(1, m_selectedTrack, m_timeline->tracksCount() - 2); - if (ix == m_timeline->audioTarget) { - m_timeline->audioTarget = -1; - } else if (m_timeline->audioTarget > ix) { - m_timeline->audioTarget--; - } - if (ix == m_timeline->videoTarget) { - m_timeline->videoTarget = -1; - } else if (m_timeline->videoTarget > ix) { - m_timeline->videoTarget--; - } - - // Delete composite transition - Mlt::Tractor *tractor = m_document->renderer()->lockService(); - QScopedPointer field(tractor->field()); - if (m_timeline->getTrackInfo(ix).type == VideoTrack) { - QScopedPointer tr(m_timeline->transitionHandler->getTrackTransition( - QStringList() << QStringLiteral("qtblend") << QStringLiteral("frei0r.cairoblend") << QStringLiteral("movit.overlay"), ix, -1)); - if (tr) { - field->disconnect_service(*tr.data()); - } - QScopedPointer mixTr(m_timeline->transitionHandler->getTrackTransition(QStringList() << QStringLiteral("mix"), ix, -1)); - if (mixTr) { - field->disconnect_service(*mixTr.data()); - } - } - // Manually remove all transitions issued from track ix, otherwise MLT will relocate it to another track - m_timeline->transitionHandler->deleteTrackTransitions(ix); - - // Delete track in MLT playlist - tractor->remove_track(ix); - m_document->renderer()->unlockService(tractor); - reloadTimeline(); - // Refresh track compositing and audio mix - m_timeline->refreshTransitions(); -} - -void CustomTrackView::configTracks(const QList &trackInfos) -{ - // TODO: fix me, use UNDO/REDO - for (int i = 0; i < trackInfos.count(); ++i) { - m_timeline->setTrackInfo(m_timeline->visibleTracksCount() - i, trackInfos.at(i)); - } - viewport()->update(); -} - -void CustomTrackView::slotSwitchTrackLock(int ix, bool enable, bool applyToAll) -{ - QUndoCommand *command = nullptr; - if (!applyToAll) { - command = new LockTrackCommand(this, ix, enable); - } else { - command = new QUndoCommand; - command->setText(i18n("Switch All Track Lock")); - for (int i = 1; i <= m_timeline->visibleTracksCount(); ++i) { - if (i == ix) { - continue; - } - new LockTrackCommand(this, i, enable, command); - } - } - m_commandStack->push(command); -} - -void CustomTrackView::lockTrack(int ix, bool lock, bool requestUpdate) -{ - m_timeline->lockTrack(ix, lock); - if (requestUpdate) { - emit doTrackLock(ix, lock); - } - AbstractClipItem *clip = nullptr; - QList selection = m_scene->items(QRectF(0, getPositionFromTrack(ix) + m_tracksHeight / 2, sceneRect().width(), m_tracksHeight / 2 - 2)); - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == GroupWidget && static_cast(selection.at(i)) != m_selectionGroup) { - if ((selection.at(i)->parentItem() != nullptr) && (m_selectionGroup != nullptr)) { - selection.removeAll(static_cast(m_selectionGroup)); - resetSelectionGroup(); - } - - bool changeGroupLock = true; - bool hasClipOnTrack = false; - QList children = selection.at(i)->childItems(); - for (int j = 0; j < children.count(); ++j) { - if (children.at(j)->isSelected()) { - if (children.at(j)->type() == AVWidget) { - emit clipItemSelected(nullptr); - } else if (children.at(j)->type() == TransitionWidget) { - emit transitionItemSelected(nullptr); - } else { - continue; - } - } - - AbstractClipItem *child = static_cast(children.at(j)); - if (child) { - if (child == m_dragItem) { - m_dragItem->setMainSelectedClip(false); - m_dragItem = nullptr; - } - - // only unlock group, if it is not locked by another track too - if (!lock && child->track() != ix && m_timeline->getTrackInfo(child->track()).isLocked) { - changeGroupLock = false; - } - - // only (un-)lock if at least one clip is on the track - if (child->track() == ix) { - hasClipOnTrack = true; - } - } - } - if (changeGroupLock && hasClipOnTrack) { - static_cast(selection.at(i))->setItemLocked(lock); - } - } else if ((selection.at(i)->type() == AVWidget || selection.at(i)->type() == TransitionWidget)) { - if (selection.at(i)->parentItem()) { - if (selection.at(i)->parentItem() == m_selectionGroup) { - selection.removeAll(static_cast(m_selectionGroup)); - resetSelectionGroup(); - } else { - // groups are handled separately - continue; - } - } - - if (selection.at(i)->isSelected()) { - if (selection.at(i)->type() == AVWidget) { - emit clipItemSelected(nullptr); - } else { - emit transitionItemSelected(nullptr); - } - } - clip = static_cast(selection.at(i)); - clip->setItemLocked(lock); - if (clip == m_dragItem) { - m_dragItem->setMainSelectedClip(false); - m_dragItem = nullptr; - } - } - } - // qCDebug(KDENLIVE_LOG) << "NEXT TRK STATE: " << m_timeline->getTrackInfo(tracknumber).isLocked; - viewport()->update(); -} - -QList CustomTrackView::checkForGroups(const QRectF &rect, bool *ok) -{ - // Check there is no group going over several tracks there, or that would result in timeline corruption - QList selection = scene()->items(rect); - *ok = true; - int maxHeight = m_tracksHeight * 1.5; - for (int i = 0; i < selection.count(); ++i) { - // Check that we don't try to move a group with clips on other tracks - if (selection.at(i)->type() == GroupWidget && (selection.at(i)->boundingRect().height() >= maxHeight)) { - *ok = false; - break; - } else if ((selection.at(i)->parentItem() != nullptr) && (selection.at(i)->parentItem()->boundingRect().height() >= maxHeight)) { - *ok = false; - break; - } - } - return selection; -} - -void CustomTrackView::slotRemoveSpace(bool multiTrack) -{ - GenTime pos; - int track = 0; - if (m_menuPosition.isNull()) { - pos = GenTime(cursorPos(), pCore->getCurrentFps()); - - QPointer d = new TrackDialog(m_timeline, parentWidget()); - d->comboTracks->setCurrentIndex(m_selectedTrack); - d->label->setText(i18n("Track")); - d->track_name->setHidden(true); - d->name_label->setHidden(true); - d->before_select->setHidden(true); - d->setWindowTitle(i18n("Remove Space")); - d->video_track->setHidden(true); - d->audio_track->setHidden(true); - if (d->exec() != QDialog::Accepted) { - delete d; - return; - } - // TODO check that this is the correct index - track = m_timeline->visibleTracksCount() - d->comboTracks->currentIndex(); - delete d; - } else { - pos = GenTime((int)(mapToScene(m_menuPosition).x()), pCore->getCurrentFps()); - track = getTrackFromPos(mapToScene(m_menuPosition).y()); - } - - if (m_timeline->isTrackLocked(track)) { - emit displayMessage(i18n("Cannot remove space in a locked track"), ErrorMessage); - return; - } - - ClipItem *item = getClipItemAtMiddlePoint(pos.frames(pCore->getCurrentFps()), track); - if (item) { - emit displayMessage(i18n("You must be in an empty space to remove space (time: %1, track: %2)", - m_document->timecode().getTimecodeFromFrames(mapToScene(m_menuPosition).x()), track), - ErrorMessage); - return; - } - int length = m_timeline->getSpaceLength(pos, track, true); - if (length <= 0) { - emit displayMessage(i18n("You must be in an empty space to remove space (time: %1, track: %2)", - m_document->timecode().getTimecodeFromFrames(mapToScene(m_menuPosition).x()), track), - ErrorMessage); - return; - } - - QList selection; - if (multiTrack) { - selection = selectAllItemsToTheRight(pos.frames(pCore->getCurrentFps())); - } else { - if (spaceToolSelectTrackOnly(track, selection, pos) == -1) { - return; - } - } - createGroupForSelectedItems(selection); - QList items; - for (QGraphicsItem *i : selection) { - if (i->type() == AVWidget || i->type() == TransitionWidget) { - items << (AbstractClipItem *)i; - } - } - GenTime timeOffset(-length, pCore->getCurrentFps()); - if (canBePasted(items, timeOffset, 0)) { - completeSpaceOperation(multiTrack ? -1 : track, timeOffset, true); - } else { - // Conflict, cannot move clips - emit displayMessage(i18n("Clip collision, cannot perform operation"), ErrorMessage); - clearSelection(); - m_operationMode = None; - } -} - -void CustomTrackView::slotInsertSpace() -{ - int pos; - int track = 0; - if (m_menuPosition.isNull()) { - pos = cursorPos(); - } else { - pos = (int)mapToScene(m_menuPosition).x(); - track = getTrackFromPos(mapToScene(m_menuPosition).y()); - } - QPointer d = new SpacerDialog(GenTime(65, pCore->getCurrentFps()), m_document->timecode(), track, m_timeline->getTracksInfo(), this); - if (d->exec() != QDialog::Accepted) { - delete d; - return; - } - GenTime spaceDuration = d->selectedDuration(); - track = d->selectedTrack(); - delete d; - - QList items; - if (track >= 0) { - if (m_timeline->isTrackLocked(track)) { - emit displayMessage(i18n("Cannot insert space in a locked track"), ErrorMessage); - return; - } - - ClipItem *item = getClipItemAtMiddlePoint(pos, track); - if (item) { - pos = item->startPos().frames(pCore->getCurrentFps()); - } - - if (spaceToolSelectTrackOnly(track, items, GenTime(pos, pCore->getCurrentFps())) == -1) { - return; - } - } else { - items = selectAllItemsToTheRight(pos); - } - createGroupForSelectedItems(items); - completeSpaceOperation(track, spaceDuration, true); -} - -void CustomTrackView::insertTimelineSpace(GenTime startPos, GenTime duration, int track, const QList &excludeList) -{ - int pos = startPos.frames(pCore->getCurrentFps()); - QRectF rect; - if (track == -1) { - // all tracks - rect = QRectF(pos, 0, sceneRect().width() - pos, m_timeline->visibleTracksCount() * m_tracksHeight); - } else { - // selected track only - rect = QRectF(pos, getPositionFromTrack(track) + m_tracksHeight / 2, sceneRect().width() - pos, m_timeline->visibleTracksCount() * 2); - } - QList items = scene()->items(rect); - QList clipsToMove; - QList transitionsToMove; - QList excludedItems; - - for (int i = 0; i < items.count(); ++i) { - if (items.at(i)->type() == AVWidget || items.at(i)->type() == TransitionWidget) { - AbstractClipItem *item = static_cast(items.at(i)); - if (m_timeline->getTrackInfo(item->track()).isLocked) { - continue; - } - if (excludeList.contains(item->info())) { - excludedItems << item; - item->setItemLocked(true); - continue; - } - if (item->type() == AVWidget) { - clipsToMove.append(item->info()); - } else if (item->type() == TransitionWidget) { - transitionsToMove.append(item->info()); - } - } - } - if (!clipsToMove.isEmpty() || !transitionsToMove.isEmpty()) { - insertSpace(clipsToMove, transitionsToMove, -1, duration, GenTime()); - } - for (AbstractClipItem *item : excludedItems) { - item->setItemLocked(false); - } -} - -void CustomTrackView::insertSpace(const QList &clipsToMove, const QList &transToMove, int track, const GenTime &duration, - const GenTime &offset) -{ - int diff = duration.frames(pCore->getCurrentFps()); - resetSelectionGroup(); - m_selectionMutex.lock(); - m_selectionGroup = new AbstractGroupItem(pCore->getCurrentFps()); - scene()->addItem(m_selectionGroup); - - // Create lists with start pos for each track - QMap trackClipStartList; - QMap trackTransitionStartList; - - for (int i = 1; i < m_timeline->tracksCount() + 1; ++i) { - trackClipStartList[i] = -1; - trackTransitionStartList[i] = -1; - } - if (!clipsToMove.isEmpty()) - for (int i = 0; i < clipsToMove.count(); ++i) { - ClipItem *clip = getClipItemAtStart(clipsToMove.at(i).startPos + offset, clipsToMove.at(i).track); - if (clip) { - if (clip->parentItem()) { - m_selectionGroup->addItem(clip->parentItem()); - } else { - m_selectionGroup->addItem(clip); - } - if (trackClipStartList.value(clipsToMove.at(i).track) == -1 || - clipsToMove.at(i).startPos.frames(pCore->getCurrentFps()) < trackClipStartList.value(clipsToMove.at(i).track)) { - trackClipStartList[clipsToMove.at(i).track] = clipsToMove.at(i).startPos.frames(pCore->getCurrentFps()); - } - } else { - emit displayMessage(i18n("Cannot move clip at position %1, track %2", - m_document->timecode().getTimecodeFromFrames((clipsToMove.at(i).startPos + offset).frames(pCore->getCurrentFps())), - clipsToMove.at(i).track), - ErrorMessage); - } - } - if (!transToMove.isEmpty()) - for (int i = 0; i < transToMove.count(); ++i) { - Transition *transition = getTransitionItemAtStart(transToMove.at(i).startPos + offset, transToMove.at(i).track); - if (transition) { - if (transition->parentItem()) { - // If group has a locked item, ungroup first - AbstractGroupItem *grp = static_cast(transition->parentItem()); - if (grp->isItemLocked()) { - m_document->clipManager()->removeGroup(grp); - if (grp == m_selectionGroup) { - m_selectionGroup = nullptr; - } - scene()->destroyItemGroup(grp); - transition->setItemLocked(false); - m_selectionGroup->addItem(transition); - } else { - m_selectionGroup->addItem(transition->parentItem()); - } - } else { - m_selectionGroup->addItem(transition); - } - if (trackTransitionStartList.value(transToMove.at(i).track) == -1 || - transToMove.at(i).startPos.frames(pCore->getCurrentFps()) < trackTransitionStartList.value(transToMove.at(i).track)) { - trackTransitionStartList[transToMove.at(i).track] = transToMove.at(i).startPos.frames(pCore->getCurrentFps()); - } - } else { - emit displayMessage(i18n("Cannot move transition at position %1, track %2", - m_document->timecode().getTimecodeFromFrames(transToMove.at(i).startPos.frames(pCore->getCurrentFps())), - transToMove.at(i).track), - ErrorMessage); - } - } - - m_selectionGroup->setTransform(QTransform::fromTranslate(diff, 0), true); - - // update items coordinates - QList itemList = m_selectionGroup->childItems(); - QList groupList; - - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget || itemList.at(i)->type() == TransitionWidget) { - int realTrack = getTrackFromPos(itemList.at(i)->scenePos().y()); - static_cast(itemList.at(i))->updateItem(realTrack); - } else if (itemList.at(i)->type() == GroupWidget) { - AbstractGroupItem *group = static_cast(itemList.at(i)); - groupList << group; - m_document->clipManager()->removeGroup(group); - QList children = itemList.at(i)->childItems(); - for (int j = 0; j < children.count(); ++j) { - AbstractClipItem *clp = static_cast(children.at(j)); - int realTrack = getTrackFromPos(clp->scenePos().y()); - clp->updateItem(realTrack); - } - } - } - m_selectionMutex.unlock(); - resetSelectionGroup(false); - // Rebuild groups after translate - for (AbstractGroupItem *grp : groupList) { - rebuildGroup(grp); - } - m_document->renderer()->mltInsertSpace(trackClipStartList, trackTransitionStartList, track, duration, offset); -} - -void CustomTrackView::deleteClip(const QString &clipId, QUndoCommand *deleteCommand) -{ - resetSelectionGroup(); - QList itemList = items(); - int count = 0; - QList range; - RefreshMonitorCommand *firstRefresh = new RefreshMonitorCommand(this, ItemInfo(), false, true, deleteCommand); - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget) { - ClipItem *item = static_cast(itemList.at(i)); - if (item->getBinId() == clipId) { - count++; - if (item->hasVisibleVideo()) { - range << item->info(); - } - if (item->parentItem()) { - // Clip is in a group, destroy the group - new GroupClipsCommand(this, QList() << item->info(), QList(), false, true, deleteCommand); - } - new AddTimelineClipCommand(this, item->getBinId(), item->info(), item->effectList(), item->clipState(), true, true, false, deleteCommand); - // Check if it is a title clip with automatic transition, than remove it - if (item->clipType() == Text) { - Transition *tr = getTransitionItemAtStart(item->startPos(), item->track()); - if ((tr != nullptr) && tr->endPos() == item->endPos()) { - new AddTransitionCommand(this, tr->info(), tr->transitionEndTrack(), tr->toXML(), true, true, deleteCommand); - } - } - } - } - } - if (count > 0) { - firstRefresh->updateRange(range); - new RefreshMonitorCommand(this, range, true, false, deleteCommand); - updateTrackDuration(-1, deleteCommand); - } -} - -void CustomTrackView::seekCursorPos(int pos) -{ - emit updateRuler(pos); - m_document->renderer()->seek(pos); -} - -int CustomTrackView::seekPosition() const -{ - int seek = m_document->renderer()->requestedSeekPosition; - if (seek == SEEK_INACTIVE) { - return m_cursorPos; - } - return seek; -} - -void CustomTrackView::setCursorPos(int pos) -{ - if (pos != m_cursorPos) { - emit cursorMoved(m_cursorPos, pos); - if (m_moveOpMode == RollingStart || m_moveOpMode == RollingEnd) { - TrimManager *mgr = qobject_cast(m_toolManagers.value(AbstractToolManager::TrimType)); - mgr->moveRoll(pos > m_cursorPos, pos); - } - m_cursorPos = pos; - m_cursorLine->setPos(m_cursorPos + m_cursorOffset, 0); - if (m_autoScroll) { - checkScrolling(); - } - } - // else emit updateRuler(); -} - -int CustomTrackView::cursorPos() const -{ - return m_cursorPos; -} - -void CustomTrackView::moveCursorPos(int delta) -{ - int currentPos = m_document->renderer()->requestedSeekPosition; - if (currentPos == SEEK_INACTIVE) { - currentPos = m_document->renderer()->seekFramePosition() + delta; - } else { - currentPos += delta; - } - emit updateRuler(currentPos); - m_document->renderer()->seek(qMax(0, currentPos)); -} - -void CustomTrackView::initCursorPos(int pos) -{ - emit cursorMoved(m_cursorPos, pos); - m_cursorPos = pos; - m_cursorLine->setPos(m_cursorPos + 0.5, 0); - checkScrolling(); -} - -void CustomTrackView::checkScrolling() -{ - double xPos = seekPosition(); - QRectF viewRect = mapToScene(rect()).boundingRect(); - if (xPos - viewRect.left() < 50 || viewRect.right() - xPos < 50) { - QGraphicsView::ViewportUpdateMode mode = viewportUpdateMode(); - setViewportUpdateMode(QGraphicsView::FullViewportUpdate); - ensureVisible(xPos, viewRect.top() + 5, 2, 2, 50, 0); - setViewportUpdateMode(mode); - } -} - -void CustomTrackView::scrollToStart() -{ - horizontalScrollBar()->setValue(0); -} - -void CustomTrackView::completeSpaceOperation(int track, GenTime &timeOffset, bool fromStart) -{ - QList groups; - - if (timeOffset != GenTime()) { - QList items = m_selectionGroup->childItems(); - - QList clipsToMove; - QList transitionsToMove; - - // Create lists with start pos for each track - QMap trackClipStartList; - QMap trackTransitionStartList; - - for (int i = 1; i < m_timeline->tracksCount() + 1; ++i) { - trackClipStartList[i] = -1; - trackTransitionStartList[i] = -1; - } - for (int i = 0; i < items.count(); ++i) { - if (items.at(i)->type() == GroupWidget) { - AbstractGroupItem *group = static_cast(items.at(i)); - if (!groups.contains(group)) { - groups.append(group); - } - items += items.at(i)->childItems(); - } - } - - for (int i = 0; i < items.count(); ++i) { - if (items.at(i)->type() == AVWidget) { - AbstractClipItem *item = static_cast(items.at(i)); - ItemInfo info = item->info(); - clipsToMove.append(info); - int realTrack = getTrackFromPos(item->scenePos().y()); - item->updateItem(realTrack); - if (trackClipStartList.value(info.track) == -1 || info.startPos.frames(pCore->getCurrentFps()) < trackClipStartList.value(info.track)) { - trackClipStartList[info.track] = info.startPos.frames(pCore->getCurrentFps()); - } - } else if (items.at(i)->type() == TransitionWidget) { - AbstractClipItem *item = static_cast(items.at(i)); - ItemInfo info = item->info(); - transitionsToMove.append(info); - int realTrack = getTrackFromPos(item->scenePos().y()); - item->updateItem(realTrack); - if (trackTransitionStartList.value(info.track) == -1 || - info.startPos.frames(pCore->getCurrentFps()) < trackTransitionStartList.value(info.track)) { - trackTransitionStartList[info.track] = info.startPos.frames(pCore->getCurrentFps()); - } - } - } - if (!clipsToMove.isEmpty() || !transitionsToMove.isEmpty()) { - auto *command = new QUndoCommand; - command->setText(timeOffset < GenTime() ? i18n("Remove space") : i18n("Insert space")); - // TODO: break groups upstream - breakLockedGroups(clipsToMove, transitionsToMove, command, fromStart); - new InsertSpaceCommand(this, clipsToMove, transitionsToMove, track, timeOffset, fromStart, command); - updateTrackDuration(track, command); - m_commandStack->push(command); - if (!fromStart) { - m_document->renderer()->mltInsertSpace(trackClipStartList, trackTransitionStartList, track, timeOffset, GenTime()); - } - } - } - resetSelectionGroup(); - if (!fromStart) - for (int i = 0; i < groups.count(); ++i) { - rebuildGroup(groups.at(i)); - } - - clearSelection(); - m_operationMode = None; -} - -void CustomTrackView::mouseReleaseEvent(QMouseEvent *event) -{ - if (event->button() != Qt::LeftButton) { - QGraphicsView::mouseReleaseEvent(event); - return; - } - - if ((event->modifiers() & Qt::ControlModifier) != 0u) { - event->ignore(); - } - - QGraphicsView::mouseReleaseEvent(event); - setDragMode(QGraphicsView::NoDrag); - - if (m_moveOpMode == Seek || m_moveOpMode == ScrollTimeline || m_moveOpMode == ZoomTimeline) { - m_moveOpMode = None; - return; - } - m_clipDrag = false; - - /*if (m_dragItem == nullptr && m_selectionGroup == nullptr) { - emit transitionItemSelected(nullptr); - m_moveOpMode = None; - return; - }*/ - QPointF clickPoint = mapToScene(event->pos()); - GenTime clickFrame(clickPoint.x(), pCore->getCurrentFps()); - m_currentToolManager->mouseRelease(event, m_selectionGroup ? m_selectionGroup->startPos() : GenTime()); - if (m_tool == SelectTool && m_currentToolManager->type() != AbstractToolManager::SelectType) { - m_currentToolManager->closeTool(); - m_currentToolManager = m_toolManagers.value(AbstractToolManager::SelectType); - m_currentToolManager->initTool(m_tracksHeight * m_scene->scale().y()); - } - m_moveOpMode = None; -} - -void CustomTrackView::deleteClip(const ItemInfo &info, bool refresh) -{ - ClipItem *item = getClipItemAtStart(info.startPos, info.track, info.endPos); - m_ct++; - if (!item) { - return; - } - // m_document->renderer()->saveSceneList(QString("/tmp/error%1.mlt").arg(m_ct), QDomElement()); - if (!m_timeline->track(info.track)->del(info.startPos.seconds())) { - qCDebug(KDENLIVE_LOG) << " / / /CANNOT DELETE CLIP AT: " << info.startPos.frames(25); - emit displayMessage(i18n("Error removing clip at %1 on track %2", - m_document->timecode().getTimecodeFromFrames(info.startPos.frames(pCore->getCurrentFps())), - m_timeline->getTrackInfo(info.track).trackName), - ErrorMessage); - return; - } - item->stopThumbs(); - item->binClip()->removeRef(); - if (item->isSelected()) { - emit clipItemSelected(nullptr); - } - if (m_dragItem == item) { - m_dragItem->setMainSelectedClip(false); - m_dragItem = nullptr; - } - if (refresh && !item->hasVisibleVideo()) { - refresh = false; - } - delete item; - item = nullptr; - if (refresh) { - monitorRefresh(info, true); - } -} - -void CustomTrackView::deleteSelectedClips() -{ - resetSelectionGroup(); - QList itemList = scene()->selectedItems(); - if (itemList.isEmpty()) { - emit displayMessage(i18n("Select clip to delete"), ErrorMessage); - return; - } - scene()->clearSelection(); - auto *deleteSelected = new QUndoCommand(); - RefreshMonitorCommand *firstRefresh = new RefreshMonitorCommand(this, ItemInfo(), false, true, deleteSelected); - - int groupCount = 0; - int clipCount = 0; - int transitionCount = 0; - // expand & destroy groups - QList range; - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == GroupWidget) { - groupCount++; - QList children = itemList.at(i)->childItems(); - QList clipInfos; - QList transitionInfos; - for (int j = 0; j < children.count(); ++j) { - if (children.at(j)->type() == AVWidget) { - AbstractClipItem *clip = static_cast(children.at(j)); - if (!clip->isItemLocked()) { - clipInfos.append(clip->info()); - } - } else if (children.at(j)->type() == TransitionWidget) { - AbstractClipItem *clip = static_cast(children.at(j)); - if (!clip->isItemLocked()) { - transitionInfos.append(clip->info()); - } - } - if (itemList.contains(children.at(j))) { - children.removeAt(j); - j--; - } - } - itemList += children; - if (!clipInfos.isEmpty()) { - new GroupClipsCommand(this, clipInfos, transitionInfos, false, true, deleteSelected); - } - - } else if ((itemList.at(i)->parentItem() != nullptr) && itemList.at(i)->parentItem()->type() == GroupWidget) { - itemList.insert(i + 1, itemList.at(i)->parentItem()); - } - } - emit clipItemSelected(nullptr); - emit transitionItemSelected(nullptr); - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget) { - clipCount++; - ClipItem *item = static_cast(itemList.at(i)); - new AddTimelineClipCommand(this, item->getBinId(), item->info(), item->effectList(), item->clipState(), true, true, false, deleteSelected); - // Check if it is a title clip with automatic transition, than remove it - if (item->clipType() == Text) { - Transition *tr = getTransitionItemAtStart(item->startPos(), item->track()); - if ((tr != nullptr) && !itemList.contains(tr) && tr->isAutomatic() && tr->endPos() == item->endPos()) { - new AddTransitionCommand(this, tr->info(), tr->transitionEndTrack(), tr->toXML(), true, true, deleteSelected); - } - } - } else if (itemList.at(i)->type() == TransitionWidget) { - transitionCount++; - Transition *item = static_cast(itemList.at(i)); - new AddTransitionCommand(this, item->info(), item->transitionEndTrack(), item->toXML(), true, true, deleteSelected); - } - } - if (groupCount > 0 && clipCount == 0 && transitionCount == 0) { - deleteSelected->setText(i18np("Delete selected group", "Delete selected groups", groupCount)); - } else if (clipCount > 0 && groupCount == 0 && transitionCount == 0) { - deleteSelected->setText(i18np("Delete selected clip", "Delete selected clips", clipCount)); - } else if (transitionCount > 0 && groupCount == 0 && clipCount == 0) { - deleteSelected->setText(i18np("Delete selected transition", "Delete selected transitions", transitionCount)); - } else { - deleteSelected->setText(i18n("Delete selected items")); - } - updateTrackDuration(-1, deleteSelected); - firstRefresh->updateRange(range); - new RefreshMonitorCommand(this, range, true, false, deleteSelected); - m_commandStack->push(deleteSelected); -} - -void CustomTrackView::doChangeClipSpeed(const ItemInfo &info, const ItemInfo &speedIndependantInfo, PlaylistState::ClipState state, const double speed, - int strobe, const QString &id, bool removeEffect) -{ - ClipItem *item = getClipItemAtStart(info.startPos, info.track); - if (!item) { - // qCDebug(KDENLIVE_LOG) << "ERROR: Cannot find clip for speed change"; - emit displayMessage(i18n("Cannot find clip for speed change"), ErrorMessage); - return; - } - if (speed == item->speed()) { - // Nothing to do, abort - return; - } - int endPos = m_timeline->changeClipSpeed(info, speedIndependantInfo, state, speed, strobe, m_document->renderer()->getBinProducer(id), removeEffect); - if (endPos >= 0) { - item->setSpeed(speed, strobe); - item->updateRectGeometry(); - if (item->cropDuration().frames(pCore->getCurrentFps()) != endPos - 1) { - item->resizeEnd((int)info.startPos.frames(pCore->getCurrentFps()) + endPos); - } - updatePositionEffects(item, info, false); - } else { - emit displayMessage(i18n("Invalid clip"), ErrorMessage); - } -} - -void CustomTrackView::cutSelectedClips(QList itemList, GenTime currentPos) -{ - if (itemList.isEmpty()) { - itemList = scene()->selectedItems(); - } - QList groups; - if (currentPos == GenTime()) { - currentPos = GenTime(m_cursorPos, pCore->getCurrentFps()); - } - if (itemList.isEmpty()) { - // Fetch clip on selected track / under cursor - ClipItem *under = getClipItemAtMiddlePoint(m_cursorPos, m_selectedTrack); - if (under) { - itemList << under; - } - } - auto *command = new QUndoCommand; - command->setText(i18n("Razor clip")); - for (int i = 0; i < itemList.count(); ++i) { - if (!itemList.at(i)) { - continue; - } - if (itemList.at(i)->type() == AVWidget) { - ClipItem *item = static_cast(itemList.at(i)); - if ((item->parentItem() != nullptr) && item->parentItem() != m_selectionGroup) { - AbstractGroupItem *group = static_cast(item->parentItem()); - if (!groups.contains(group)) { - groups << group; - } - } else if (currentPos > item->startPos() && currentPos < item->endPos()) { - new RazorClipCommand(this, item->info(), item->effectList(), currentPos, true, command); - } - } else if (itemList.at(i)->type() == GroupWidget && itemList.at(i) != m_selectionGroup) { - AbstractGroupItem *group = static_cast(itemList.at(i)); - if (!groups.contains(group)) { - groups << group; - } - } - } - if (command->childCount() > 0) { - m_commandStack->push(command); - } else { - delete command; - } - - for (int i = 0; i < groups.count(); ++i) { - razorGroup(groups.at(i), currentPos); - } -} - -void CustomTrackView::razorGroup(AbstractGroupItem *group, GenTime cutPos) -{ - if (group) { - QList children = group->childItems(); - auto *command = new QUndoCommand; - command->setText(i18n("Cut Group")); - groupClips(false, children, false, command); - QList clips1, transitions1; - QList transitionsCut; - QList clips2, transitions2; - QVector clipsToCut; - - // Collect info - for (int i = 0; i < children.count(); ++i) { - children.at(i)->setSelected(false); - AbstractClipItem *child = static_cast(children.at(i)); - if (!child) { - continue; - } - if (child->type() == AVWidget) { - if (cutPos >= child->endPos()) { - clips1 << child->info(); - } else if (cutPos <= child->startPos()) { - clips2 << child->info(); - } else { - clipsToCut << child; - } - } else { - if (cutPos > child->endPos()) { - transitions1 << child->info(); - } else if (cutPos < child->startPos()) { - transitions2 << child->info(); - } else { - // transitionsCut << child->info(); - // Transition cut not implemented, leave it in first group... - transitions1 << child->info(); - } - } - } - if (clipsToCut.isEmpty() && transitionsCut.isEmpty() && - ((clips1.isEmpty() && transitions1.isEmpty()) || (clips2.isEmpty() && transitions2.isEmpty()))) { - delete command; - return; - } - // Process the cut - for (int i = 0; i < clipsToCut.count(); ++i) { - ClipItem *clip = static_cast(clipsToCut.at(i)); - new RazorClipCommand(this, clip->info(), clip->effectList(), cutPos, true, command); - ItemInfo info = clip->info(); - info.endPos = GenTime(cutPos.frames(pCore->getCurrentFps()) - 1, pCore->getCurrentFps()); - info.cropDuration = info.endPos - info.startPos; - ItemInfo cutInfo = info; - cutInfo.startPos = cutPos; - cutInfo.cropDuration = cutInfo.endPos - cutInfo.startPos; - clips1 << info; - clips2 << cutInfo; - } - new GroupClipsCommand(this, clips1, transitions1, true, true, command); - new GroupClipsCommand(this, clips2, transitions2, true, true, command); - m_commandStack->push(command); - } -} - -void CustomTrackView::groupClips(bool group, QList itemList, bool forceLock, QUndoCommand *command, bool doIt) -{ - if (itemList.isEmpty()) { - itemList = scene()->selectedItems(); - } - QList clipInfos; - QList transitionInfos; - QList existingGroups; - - // Expand groups - int max = itemList.count(); - for (int i = 0; i < max; ++i) { - QGraphicsItem *item = itemList.at(i); - if (item->type() == GroupWidget && item != m_selectionGroup) { - if (!existingGroups.contains(item)) { - existingGroups << item; - } - itemList += item->childItems(); - } else if ((item->parentItem() != nullptr) && item->parentItem()->type() == GroupWidget) { - AbstractGroupItem *grp = static_cast(item->parentItem()); - itemList += grp->childItems(); - } - } - QList processedClips; - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget) { - AbstractClipItem *clip = static_cast(itemList.at(i)); - if (!processedClips.contains(clip) && (forceLock || !clip->isItemLocked())) { - clipInfos.append(clip->info()); - processedClips << clip; - } - } else if (itemList.at(i)->type() == TransitionWidget) { - AbstractClipItem *clip = static_cast(itemList.at(i)); - if (!processedClips.contains(clip) && (forceLock || !clip->isItemLocked())) { - transitionInfos.append(clip->info()); - processedClips << clip; - } - } - } - if (!clipInfos.isEmpty()) { - // break previous groups - QUndoCommand *metaCommand = nullptr; - if (group && (command == nullptr) && !existingGroups.isEmpty()) { - metaCommand = new QUndoCommand(); - metaCommand->setText(i18n("Group clips")); - } - for (int i = 0; group && i < existingGroups.count(); ++i) { - AbstractGroupItem *grp = static_cast(existingGroups.at(i)); - QList clipGrpInfos; - QList transitionGrpInfos; - QList items = grp->childItems(); - for (int j = 0; j < items.count(); ++j) { - if (items.at(j)->type() == AVWidget) { - AbstractClipItem *clip = static_cast(items.at(j)); - if (forceLock || !clip->isItemLocked()) { - clipGrpInfos.append(clip->info()); - } - } else if (items.at(j)->type() == TransitionWidget) { - AbstractClipItem *clip = static_cast(items.at(j)); - if (forceLock || !clip->isItemLocked()) { - transitionGrpInfos.append(clip->info()); - } - } - } - if (!clipGrpInfos.isEmpty() || !transitionGrpInfos.isEmpty()) { - if (command) { - new GroupClipsCommand(this, clipGrpInfos, transitionGrpInfos, false, doIt, command); - } else { - new GroupClipsCommand(this, clipGrpInfos, transitionGrpInfos, false, doIt, metaCommand); - } - if (!doIt) { - // Action must be performed right now - doGroupClips(clipGrpInfos, transitionGrpInfos, false); - } - } - } - if (command) { - // Create new group - new GroupClipsCommand(this, clipInfos, transitionInfos, group, doIt, command); - } else { - if (metaCommand) { - new GroupClipsCommand(this, clipInfos, transitionInfos, group, doIt, metaCommand); - m_commandStack->push(metaCommand); - } else { - auto *groupCommand = new GroupClipsCommand(this, clipInfos, transitionInfos, group, doIt); - m_commandStack->push(groupCommand); - } - } - if (!doIt) { - // Action must be performed right now - doGroupClips(clipInfos, transitionInfos, group); - } - } -} - -void CustomTrackView::doGroupClips(const QList &clipInfos, const QList &transitionInfos, bool group) -{ - resetSelectionGroup(); - m_scene->clearSelection(); - if (!group) { - // ungroup, find main group to destroy it... - for (int i = 0; i < clipInfos.count(); ++i) { - ClipItem *clip = getClipItemAtStart(clipInfos.at(i).startPos, clipInfos.at(i).track); - if (clip == nullptr) { - qCDebug(KDENLIVE_LOG) << " * ** Cannot find UNGROUP clip at: " << clipInfos.at(i).startPos.frames(25) << " / " << clipInfos.at(i).track; - continue; - } - if ((clip->parentItem() != nullptr) && clip->parentItem()->type() == GroupWidget) { - AbstractGroupItem *grp = static_cast(clip->parentItem()); - m_document->clipManager()->removeGroup(grp); - if (grp == m_selectionGroup) { - m_selectionGroup = nullptr; - } - scene()->destroyItemGroup(grp); - } - clip->setItemLocked(m_timeline->getTrackInfo(clip->track()).isLocked); - } - for (int i = 0; i < transitionInfos.count(); ++i) { - Transition *tr = getTransitionItemAt(transitionInfos.at(i).startPos, transitionInfos.at(i).track); - if (tr == nullptr) { - continue; - } - if ((tr->parentItem() != nullptr) && tr->parentItem()->type() == GroupWidget) { - AbstractGroupItem *grp = static_cast(tr->parentItem()); - m_document->clipManager()->removeGroup(grp); - if (grp == m_selectionGroup) { - m_selectionGroup = nullptr; - } - scene()->destroyItemGroup(grp); - grp = nullptr; - } - tr->setItemLocked(m_timeline->getTrackInfo(tr->track()).isLocked); - } - return; - } - QList list; - for (int i = 0; i < clipInfos.count(); ++i) { - ClipItem *clip = getClipItemAtStart(clipInfos.at(i).startPos, clipInfos.at(i).track); - if ((clip != nullptr) && !list.contains(clip)) { - list.append(clip); - // clip->setSelected(true); - } - } - for (int i = 0; i < transitionInfos.count(); ++i) { - Transition *clip = getTransitionItemAt(transitionInfos.at(i).startPos, transitionInfos.at(i).track); - if ((clip != nullptr) && !list.contains(clip)) { - list.append(clip); - // clip->setSelected(true); - } - } - groupSelectedItems(list, true, true); -} - -void CustomTrackView::slotInfoProcessingFinished() -{ - m_producerNotReady.wakeAll(); -} - -void CustomTrackView::addClip(const QString &clipId, const ItemInfo &info, const EffectsList &effects, PlaylistState::ClipState state, bool refresh) -{ - /* - ProjectClip *binClip = m_document->getBinClip(clipId); - if (!binClip) { - emit displayMessage(i18n("Cannot insert clip."), ErrorMessage); - return; - } - if (!binClip->isReady()) { - // If the clip has no producer, we must wait until it is created... - emit displayMessage(i18n("Waiting for clip..."), InformationMessage); - m_document->forceProcessing(clipId); - // If the clip is not ready, give it 10x3 seconds to complete the task... - for (int i = 0; i < 10; ++i) { - if (!binClip->isReady()) { - m_mutex.lock(); - m_producerNotReady.wait(&m_mutex, 3000); - m_mutex.unlock(); - } else { - break; - } - } - if (!binClip->isReady()) { - emit displayMessage(i18n("Cannot insert clip..."), ErrorMessage); - return; - } - emit displayMessage(QString(), InformationMessage); - } - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - // Get speed and strobe values from effects - double speed = 1.0; - int strobe = 1; - QDomElement speedEffect = effects.effectById(QStringLiteral("speed")); - if (!speedEffect.isNull()) { - QDomNodeList nodes = speedEffect.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < nodes.count(); ++i) { - QDomElement e = nodes.item(i).toElement(); - if (e.attribute(QStringLiteral("name")) == QLatin1String("speed")) { - speed = locale.toDouble(e.attribute(QStringLiteral("value"), QStringLiteral("1"))); - int factor = e.attribute(QStringLiteral("factor"), QStringLiteral("1")).toInt(); - speed /= factor; - if (speed == 0) { - speed = 1; - } - } else if (e.attribute(QStringLiteral("name")) == QLatin1String("strobe")) { - strobe = e.attribute(QStringLiteral("value"), QStringLiteral("1")).toInt(); - } - } - } - auto *item = new ClipItem(binClip, info, pCore->getCurrentFps(), speed, strobe, getFrameWidth()); - connect(item, &AbstractClipItem::selectItem, this, &CustomTrackView::slotSelectItem); - item->setPos(info.startPos.frames(pCore->getCurrentFps()), getPositionFromTrack(info.track) + 1 + item->itemOffset()); - item->setState(state); - item->setEffectList(effects); - scene()->addItem(item); - bool isLocked = m_timeline->getTrackInfo(info.track).isLocked; - if (isLocked) { - item->setItemLocked(true); - } - bool duplicate = true; - Mlt::Producer *prod; - if (speed != 1.0) { - prod = m_document->renderer()->getBinProducer(clipId); - QString url = QString::fromUtf8(prod->get("resource")); - // url.append(QLatin1Char('?') + locale.toString(speed)); - Track::SlowmoInfo slowInfo; - slowInfo.speed = speed; - slowInfo.strobe = strobe; - slowInfo.state = state; - Mlt::Producer *copy = m_document->renderer()->getSlowmotionProducer(slowInfo.toString(locale) + url); - if (copy == nullptr) { - url.prepend(locale.toString(speed) + QLatin1Char(':')); - Mlt::Properties passProperties; - Mlt::Properties original(prod->get_properties()); - passProperties.pass_list(original, ClipController::getPassPropertiesList(false)); - copy = m_timeline->track(info.track)->buildSlowMoProducer(passProperties, url, clipId, slowInfo); - } - if (copy == nullptr) { - emit displayMessage(i18n("Cannot insert clip..."), ErrorMessage); - return; - } - prod = copy; - duplicate = false; - } else if (item->clipState() == PlaylistState::VideoOnly) { - prod = m_document->renderer()->getBinVideoProducer(clipId); - } else { - prod = m_document->renderer()->getBinProducer(clipId); - } - binClip->addRef(); - m_timeline->track(info.track) - ->add(info.startPos.seconds(), prod, info.cropStart.seconds(), (info.cropStart + info.cropDuration).seconds(), state, duplicate, - TimelineMode::NormalEdit); // m_scene->editMode()); - - for (int i = 0; i < item->effectsCount(); ++i) { - m_timeline->track(info.track)->addEffect(info.startPos.seconds(), EffectsController::getEffectArgs(item->effect(i))); - } - if (refresh && item->hasVisibleVideo()) { - monitorRefresh(info, true); - } - */ -} - -void CustomTrackView::slotUpdateClip(const QString &clipId, bool reload) -{ - QMutexLocker locker(&m_mutex); - QList list = scene()->items(); - QList clipList; - ClipItem *clip = nullptr; - // TODO: move the track replacement code in track.cpp - Mlt::Tractor *tractor = m_document->renderer()->lockService(); - for (int i = 0; i < list.size(); ++i) { - if (list.at(i)->type() == AVWidget) { - clip = static_cast(list.at(i)); - if (clip->getBinId() == clipId) { - // TODO: get audio / video only producers - /*ItemInfo info = clip->info(); - if (clip->isAudioOnly()) prod = baseClip->getTrackProducer(info.track); - else if (clip->isVideoOnly()) prod = baseClip->getTrackProducer(info.track); - else prod = baseClip->getTrackProducer(info.track);*/ - if (reload) { - /*Mlt::Producer *prod = m_document->renderer()->getTrackProducer(clipId, info.track, clip->isAudioOnly(), clip->isVideoOnly()); - if (!m_document->renderer()->mltUpdateClip(tractor, info, clip->xml(), prod)) { - emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", info.startPos.frames(pCore->getCurrentFps()), info.track), - ErrorMessage); - }*/ - } else { - clipList.append(clip); - } - } - } - } - for (int i = 0; i < clipList.count(); ++i) { - clipList.at(i)->refreshClip(true, true); - } - m_document->renderer()->unlockService(tractor); -} - -ClipItem *CustomTrackView::getClipItemAtEnd(GenTime pos, int track) -{ - int framepos = (int)(pos.frames(pCore->getCurrentFps())); - QList list = scene()->items(QPointF(framepos - 1, getPositionFromTrack(track) + m_tracksHeight / 2)); - ClipItem *clip = nullptr; - for (int i = 0; i < list.size(); ++i) { - if (!list.at(i)->isEnabled()) { - continue; - } - if (list.at(i)->type() == AVWidget) { - ClipItem *test = static_cast(list.at(i)); - if (test->endPos() == pos) { - clip = test; - } - break; - } - } - return clip; -} - -ClipItem *CustomTrackView::getClipItemAtStart(GenTime pos, int track, GenTime end) -{ - QList list = scene()->items(QPointF(pos.frames(pCore->getCurrentFps()), getPositionFromTrack(track) + m_tracksHeight / 2)); - ClipItem *clip = nullptr; - for (int i = 0; i < list.size(); ++i) { - if (!list.at(i)->isEnabled()) { - /*ClipItem *test = static_cast (list.at(i)); - qCDebug(KDENLIVE_LOG)<<" * * *DISABLED CLIP: "<startPos().frames(25);*/ - continue; - } - if (list.at(i)->type() == AVWidget) { - ClipItem *test = static_cast(list.at(i)); - // qCDebug(KDENLIVE_LOG)<<" * * *ENABLED CLIP: "<startPos().frames(25)<<" = "<startPos() == pos) { - if (end > GenTime()) { - if (test->endPos() != end) { - // qCDebug(KDENLIVE_LOG)<<" - - - -- - -NO END MATCH: "<endPos().frames(25)<<" = "<< end.frames(25); - continue; - } - } - clip = test; - break; - } - } - } - return clip; -} - -ClipItem *CustomTrackView::getMovedClipItem(const ItemInfo &info, GenTime offset, int trackOffset) -{ - QList list = - scene()->items(QPointF((info.startPos + offset).frames(pCore->getCurrentFps()), getPositionFromTrack(info.track + trackOffset) + m_tracksHeight / 2)); - ClipItem *clip = nullptr; - for (int i = 0; i < list.size(); ++i) { - // if (!list.at(i)->isEnabled()) continue; - if (list.at(i)->type() == AVWidget) { - ClipItem *test = static_cast(list.at(i)); - if (test->startPos() == info.startPos) { - if (test->endPos() != info.endPos) { - continue; - } - } - clip = test; - break; - } - } - return clip; -} - -ClipItem *CustomTrackView::getClipItemAtMiddlePoint(int pos, int track) -{ - const QPointF p(pos, getPositionFromTrack(track) + m_tracksHeight / 2); - QList list = scene()->items(p); - ClipItem *clip = nullptr; - for (int i = 0; i < list.size(); ++i) { - if (!list.at(i)->isEnabled()) { - continue; - } - if (list.at(i)->type() == AVWidget) { - clip = static_cast(list.at(i)); - break; - } - } - return clip; -} - -ClipItem *CustomTrackView::getUpperClipItemAt(int pos) -{ - ClipItem *clip = nullptr; - for (int i = m_timeline->tracksCount(); i > 0; i--) { - clip = getClipItemAtMiddlePoint(pos, i); - if (clip) { - break; - } - } - return clip; -} - -Transition *CustomTrackView::getTransitionItemAt(int pos, int track, bool alreadyMoved) -{ - const QPointF p(pos, getPositionFromTrack(track) + Transition::itemOffset() + 1); - QList list = scene()->items(p); - Transition *clip = nullptr; - for (int i = 0; i < list.size(); ++i) { - if (!alreadyMoved && !list.at(i)->isEnabled()) { - continue; - } - if (list.at(i)->type() == TransitionWidget) { - clip = static_cast(list.at(i)); - break; - } - } - return clip; -} - -Transition *CustomTrackView::getTransitionItemAt(GenTime pos, int track, bool alreadyMoved) -{ - return getTransitionItemAt(pos.frames(pCore->getCurrentFps()), track, alreadyMoved); -} - -Transition *CustomTrackView::getTransitionItemAtEnd(GenTime pos, int track) -{ - int framepos = (int)(pos.frames(pCore->getCurrentFps())); - const QPointF p(framepos - 1, getPositionFromTrack(track) + Transition::itemOffset() + 1); - QList list = scene()->items(p); - Transition *clip = nullptr; - for (int i = 0; i < list.size(); ++i) { - if (!list.at(i)->isEnabled()) { - continue; - } - if (list.at(i)->type() == TransitionWidget) { - Transition *test = static_cast(list.at(i)); - if (test->endPos() == pos) { - clip = test; - } - break; - } - } - return clip; -} - -Transition *CustomTrackView::getTransitionItemAtStart(GenTime pos, int track) -{ - const QPointF p(pos.frames(pCore->getCurrentFps()), getPositionFromTrack(track) + Transition::itemOffset() + 1); - QList list = scene()->items(p); - Transition *clip = nullptr; - for (int i = 0; i < list.size(); ++i) { - if (!list.at(i)->isEnabled()) { - continue; - } - if (list.at(i)->type() == TransitionWidget) { - Transition *test = static_cast(list.at(i)); - if (test->startPos() == pos) { - clip = test; - } - break; - } - } - return clip; -} - -bool CustomTrackView::moveClip(const ItemInfo &start, const ItemInfo &end, bool refresh, bool alreadyMoved, ItemInfo *out_actualEnd) -{ - if (m_selectionGroup) { - resetSelectionGroup(false); - } - ClipItem *item = nullptr; - if (alreadyMoved) { - item = getClipItemAtStart(end.startPos, end.track); - } else { - item = getClipItemAtStart(start.startPos, start.track); - } - if (!item) { - emit displayMessage(i18n("Cannot move clip at time: %1 on track %2", - m_document->timecode().getTimecodeFromFrames(start.startPos.frames(pCore->getCurrentFps())), start.track), - ErrorMessage); - // qCDebug(KDENLIVE_LOG) << "---------------- ERROR, CANNOT find clip to move at.. "; - return false; - } - -#ifdef DEBUG - qCDebug(KDENLIVE_LOG) << "Moving item " << (long)item << " from .. to:"; - qCDebug(KDENLIVE_LOG) << item->info(); - qCDebug(KDENLIVE_LOG) << start; - qCDebug(KDENLIVE_LOG) << end; -#endif - bool success = m_timeline->moveClip(start.track, start.startPos.seconds(), end.track, end.startPos.seconds(), item->clipState(), m_scene->editMode(), - item->needsDuplicate()); - QList range; - if (item->hasVisibleVideo()) { - range << start << end; - } else { - refresh = false; - } - if (!success) { - // undo last move and emit error message - emit displayMessage(i18n("Cannot move clip to position %1", m_document->timecode().getTimecodeFromFrames(end.startPos.frames(pCore->getCurrentFps()))), - ErrorMessage); - } else if (!alreadyMoved) { - bool snap = KdenliveSettings::snaptopoints(); - KdenliveSettings::setSnaptopoints(false); - item->setPos((int)end.startPos.frames(pCore->getCurrentFps()), getPositionFromTrack(end.track) + 1); - - bool isLocked = m_timeline->getTrackInfo(end.track).isLocked; - m_scene->clearSelection(); - if (isLocked) { - item->setItemLocked(true); - } else { - if (item->isItemLocked()) { - item->setItemLocked(false); - } - item->setSelected(true); - } - // TODO - /* - if (item->baseClip()->isTransparent()) { - // Also move automatic transition - Transition *tr = getTransitionItemAt(start.startPos, start.track); - if (tr && tr->isAutomatic()) { - tr->updateTransitionEndTrack(getPreviousVideoTrack(end.track)); - m_document->renderer()->mltMoveTransition(tr->transitionTag(), m_timeline->tracksCount() - start.track, m_timeline->tracksCount() - end.track, - tr->transitionEndTrack(), start.startPos, start.endPos, end.startPos, end.endPos); - tr->setPos((int) end.startPos.frames(pCore->getCurrentFps()), (int)(end.track * m_tracksHeight + 1)); - } - }*/ - KdenliveSettings::setSnaptopoints(snap); - } - if (refresh) { - monitorRefresh(range, true); - } - if (out_actualEnd != nullptr) { - *out_actualEnd = item->info(); -#ifdef DEBUG - qCDebug(KDENLIVE_LOG) << "Actual end position updated:" << *out_actualEnd; -#endif - } -#ifdef DEBUG - qCDebug(KDENLIVE_LOG) << item->info(); -#endif - return success; -} - -void CustomTrackView::moveGroup(QList startClip, QList startTransition, const GenTime &offset, const int trackOffset, bool alreadyMoved, - bool reverseMove) -{ - // Group Items - resetSelectionGroup(); - m_scene->clearSelection(); - m_selectionMutex.lock(); - m_selectionGroup = new AbstractGroupItem(pCore->getCurrentFps()); - scene()->addItem(m_selectionGroup); - QList range; - m_document->renderer()->blockSignals(true); - for (int i = 0; i < startClip.count(); ++i) { - if (reverseMove) { - startClip[i].startPos = startClip.at(i).startPos - offset; - startClip[i].track = startClip.at(i).track - trackOffset; - } - ClipItem *clip = nullptr; - if (alreadyMoved) { - clip = getMovedClipItem(startClip.at(i), offset, trackOffset); - } else { - clip = getClipItemAtStart(startClip.at(i).startPos, startClip.at(i).track); - } - if (clip) { - if (clip->hasVisibleVideo()) { - ItemInfo updateInfo = startClip.at(i); - range << updateInfo; - updateInfo.startPos += offset; - updateInfo.endPos += offset; - range << updateInfo; - } - if (clip->parentItem()) { - m_selectionGroup->addItem(clip->parentItem()); - // If timeline clip is already at destination, make sure it is not moved twice - if (alreadyMoved) { - clip->parentItem()->setEnabled(false); - } - } else { - m_selectionGroup->addItem(clip); - if (alreadyMoved) { - clip->setEnabled(false); - } - } - m_timeline->track(startClip.at(i).track)->del(startClip.at(i).startPos.seconds(), false); - } else { - qCDebug(KDENLIVE_LOG) << "//MISSING CLIP AT: " << startClip.at(i).startPos.frames(25) << " / track: " << startClip.at(i).track - << " / OFFSET: " << trackOffset; - } - } - for (int i = 0; i < startTransition.count(); ++i) { - if (reverseMove) { - startTransition[i].startPos = startTransition.at(i).startPos - offset; - startTransition[i].track = startTransition.at(i).track - trackOffset; - } - Transition *tr = nullptr; - if (alreadyMoved) { - tr = getTransitionItemAt(startTransition.at(i).startPos + offset, startTransition.at(i).track + trackOffset, true); - } else { - tr = getTransitionItemAt(startTransition.at(i).startPos, startTransition.at(i).track); - } - if (tr) { - ItemInfo updateInfo = startTransition.at(i); - range << updateInfo; - updateInfo.startPos += offset; - updateInfo.endPos += offset; - range << updateInfo; - if (tr->parentItem()) { - m_selectionGroup->addItem(tr->parentItem()); - if (alreadyMoved) { - tr->parentItem()->setEnabled(false); - } - } else { - m_selectionGroup->addItem(tr); - if (alreadyMoved) { - tr->setEnabled(false); - } - } - m_timeline->transitionHandler->deleteTransition(tr->transitionTag(), tr->transitionEndTrack(), startTransition.at(i).track, - startTransition.at(i).startPos, startTransition.at(i).endPos, tr->toXML()); - } else { - qCDebug(KDENLIVE_LOG) << "//MISSING TRANSITION AT: " << startTransition.at(i).startPos.frames(25) << ", track: " << startTransition.at(i).track; - } - } - m_document->renderer()->blockSignals(false); - - if (m_selectionGroup) { - bool snap = KdenliveSettings::snaptopoints(); - KdenliveSettings::setSnaptopoints(false); - - if (!alreadyMoved) { - m_selectionGroup->setTransform(QTransform::fromTranslate(offset.frames(pCore->getCurrentFps()), -trackOffset * (qreal)m_tracksHeight), true); - } - - QList children = m_selectionGroup->childItems(); - QList groupList; - // Expand groups - int max = children.count(); - for (int i = 0; i < max; ++i) { - if (children.at(i)->type() == GroupWidget) { - QList groupChildren = children.at(i)->childItems(); - for (int j = 0; j < groupChildren.count(); j++) { - AbstractClipItem *item = static_cast(groupChildren.at(j)); - ItemInfo nfo = item->info(); - item->updateItem(nfo.track + trackOffset); - } - children += groupChildren; - // AbstractGroupItem *grp = static_cast(children.at(i)); - // grp->moveBy(offset.frames(pCore->getCurrentFps()), trackOffset *(qreal) m_tracksHeight); - /*m_document->clipManager()->removeGroup(grp); - m_scene->destroyItemGroup(grp);*/ - AbstractGroupItem *group = static_cast(children.at(i)); - if (!groupList.contains(group)) { - groupList.append(group); - } - children.removeAll(children.at(i)); - --i; - } - } - for (int i = 0; i < children.count(); ++i) { - // re-add items in correct place - if (children.at(i)->type() != AVWidget && children.at(i)->type() != TransitionWidget) { - continue; - } - AbstractClipItem *item = static_cast(children.at(i)); - item->setEnabled(true); - ItemInfo info = item->info(); - bool isLocked = m_timeline->getTrackInfo(info.track).isLocked; - if (isLocked) { - item->setItemLocked(true); - } - - if (item->type() == AVWidget) { - ClipItem *clip = static_cast(item); - Mlt::Producer *prod; - if (clip->clipState() == PlaylistState::VideoOnly) { - prod = m_document->renderer()->getBinVideoProducer(clip->getBinId()); - } else { - prod = m_document->renderer()->getBinProducer(clip->getBinId()); - } - m_timeline->track(info.track) - ->add(info.startPos.seconds(), prod, info.cropStart.seconds(), (info.cropStart + info.cropDuration).seconds(), clip->clipState(), true, - m_scene->editMode()); - - for (int j = 0; j < clip->effectsCount(); ++j) { - m_timeline->track(info.track) - ->addEffect(info.startPos.seconds(), EffectsController::getEffectArgs(clip->effect(j))); - } - } else if (item->type() == TransitionWidget) { - Transition *tr = static_cast(item); - int newTrack; - if (!tr->forcedTrack()) { - newTrack = getPreviousVideoTrack(info.track); - } else { - newTrack = tr->transitionEndTrack() + trackOffset; - if (newTrack < 0 || newTrack > m_timeline->tracksCount()) { - newTrack = getPreviousVideoTrack(info.track); - } - } - tr->updateTransitionEndTrack(newTrack); - m_timeline->transitionHandler->addTransition(tr->transitionTag(), newTrack, info.track, info.startPos, info.endPos, tr->toXML()); - } - } - m_selectionMutex.unlock(); - resetSelectionGroup(true); - for (int i = 0; i < groupList.count(); ++i) { - rebuildGroup(groupList.at(i)); - } - groupSelectedItems(children, false); - m_timeline->checkDuration(); - // clearSelection(); - KdenliveSettings::setSnaptopoints(snap); - // TODO: calculate affected ranges and invalidate previews - monitorRefresh(range, true); - } else { - qCDebug(KDENLIVE_LOG) << "///////// WARNING; NO GROUP TO MOVE"; - } -} - -void CustomTrackView::moveTransition(const ItemInfo &start, const ItemInfo &end, bool refresh) -{ - Transition *item = getTransitionItemAt(start.startPos, start.track); - if (!item) { - emit displayMessage(i18n("Cannot move transition at time: %1 on track %2", - m_document->timecode().getTimecodeFromFrames(start.startPos.frames(pCore->getCurrentFps())), start.track), - ErrorMessage); - // qCDebug(KDENLIVE_LOG) << "---------------- ERROR, CANNOT find transition to move... ";// << startPos.x() * m_scale * FRAME_SIZE + 1 << ", " << - // startPos.y() * m_tracksHeight + m_tracksHeight / 2; - return; - } - - bool snap = KdenliveSettings::snaptopoints(); - KdenliveSettings::setSnaptopoints(false); - - if (end.endPos - end.startPos == start.endPos - start.startPos) { - // Transition was moved - item->setPos((int)end.startPos.frames(pCore->getCurrentFps()), getPositionFromTrack(end.track) + 1); - } else if (end.endPos == start.endPos) { - // Transition start resize - item->resizeStart((int)end.startPos.frames(pCore->getCurrentFps())); - } else if (end.startPos == start.startPos) { - // Transition end resize; - // qCDebug(KDENLIVE_LOG) << "// resize END: " << end.endPos.frames(pCore->getCurrentFps()); - item->resizeEnd((int)end.endPos.frames(pCore->getCurrentFps())); - } else { - // Move & resize - item->setPos((int)end.startPos.frames(pCore->getCurrentFps()), getPositionFromTrack(end.track) + 1); - item->resizeStart((int)end.startPos.frames(pCore->getCurrentFps())); - item->resizeEnd((int)end.endPos.frames(pCore->getCurrentFps())); - } - // item->transitionHandler->moveTransition(GenTime((int) (endPos.x() - startPos.x()), pCore->getCurrentFps())); - KdenliveSettings::setSnaptopoints(snap); - item->updateTransitionEndTrack(getPreviousVideoTrack(end.track)); - m_timeline->transitionHandler->moveTransition(item->transitionTag(), start.track, item->track(), item->transitionEndTrack(), start.startPos, start.endPos, - item->startPos(), item->endPos()); - if ((m_dragItem != nullptr) && m_dragItem == item) { - QPoint p; - ClipItem *transitionClip = getClipItemAtStart(item->startPos(), item->track()); - if ((transitionClip != nullptr) && (transitionClip->binClip() != nullptr)) { - int frameWidth = transitionClip->binClip()->getProducerIntProperty(QStringLiteral("meta.media.width")); - int frameHeight = transitionClip->binClip()->getProducerIntProperty(QStringLiteral("meta.media.height")); - double factor = transitionClip->binClip()->getProducerProperty(QStringLiteral("aspect_ratio")).toDouble(); - if (factor == 0) { - factor = 1.0; - } - p.setX((int)(frameWidth * factor + 0.5)); - p.setY(frameHeight); - } - emit transitionItemSelected(item, getPreviousVideoTrack(item->track()), p); - } - if (refresh) { - monitorRefresh(QList() << start << end, true); - } -} - -void CustomTrackView::resizeClip(const ItemInfo &start, const ItemInfo &end, bool dontWorry) -{ - bool resizeClipStart = (start.startPos != end.startPos); - ClipItem *item = getClipItemAtStart(start.startPos, start.track, start.startPos + start.cropDuration); - if (!item) { - if (dontWorry) { - return; - } - emit displayMessage(i18n("Cannot move clip at time: %1 on track %2", - m_document->timecode().getTimecodeFromFrames(start.startPos.frames(pCore->getCurrentFps())), start.track), - ErrorMessage); - // qCDebug(KDENLIVE_LOG) << "---------------- ERROR, CANNOT find clip to resize at... "; // << startPos; - return; - } - if (item->parentItem()) { - // Item is part of a group, reset group - resetSelectionGroup(); - } - - bool snap = KdenliveSettings::snaptopoints(); - KdenliveSettings::setSnaptopoints(false); - - if (resizeClipStart) { - if (m_timeline->track(start.track)->resize(start.startPos.seconds(), (end.startPos - start.startPos).seconds(), false)) { - item->resizeStart((int)end.startPos.frames(pCore->getCurrentFps())); - } else { - emit displayMessage(i18n("Resizing clip start failed!!"), ErrorMessage); - } - } else { - if (m_timeline->track(start.track)->resize(start.startPos.seconds(), (end.endPos - start.endPos).seconds(), true)) { - item->resizeEnd((int)end.endPos.frames(pCore->getCurrentFps())); - } else { - emit displayMessage(i18n("Resizing clip end failed!!"), ErrorMessage); - } - } - - if (!resizeClipStart && end.cropStart != start.cropStart) { - // qCDebug(KDENLIVE_LOG) << "// RESIZE CROP, DIFF: " << (end.cropStart - start.cropStart).frames(25); - ItemInfo clipinfo = end; - clipinfo.track = end.track; - bool success = m_document->renderer()->mltResizeClipCrop(clipinfo, end.cropStart); - if (success) { - item->setCropStart(end.cropStart); - item->resetThumbs(true); - } - } - if (item->hasVisibleVideo()) { - ItemInfo range; - if (resizeClipStart) { - if (start.startPos < end.startPos) { - range.startPos = start.startPos; - range.endPos = end.startPos; - } else { - range.startPos = end.startPos; - range.endPos = start.startPos; - } - } else { - if (start.endPos < end.endPos) { - range.startPos = start.endPos; - range.endPos = end.endPos; - } else { - range.startPos = end.endPos; - range.endPos = start.endPos; - } - } - monitorRefresh(range, true); - } - if (item == m_dragItem) { - // clip is selected, update effect stack - emit clipItemSelected(item); - } - KdenliveSettings::setSnaptopoints(snap); -} - -void CustomTrackView::prepareResizeClipStart(AbstractClipItem *item, const ItemInfo &oldInfo, int pos, bool check, QUndoCommand *command) -{ - if (pos == oldInfo.startPos.frames(pCore->getCurrentFps())) { - return; - } - bool snap = KdenliveSettings::snaptopoints(); - if (check) { - KdenliveSettings::setSnaptopoints(false); - item->resizeStart(pos); - if (item->startPos().frames(pCore->getCurrentFps()) != pos) { - item->resizeStart(oldInfo.startPos.frames(pCore->getCurrentFps())); - emit displayMessage(i18n("Not possible to resize"), ErrorMessage); - KdenliveSettings::setSnaptopoints(snap); - return; - } - KdenliveSettings::setSnaptopoints(snap); - } - - bool hasParentCommand = false; - if (command) { - hasParentCommand = true; - } else { - command = new QUndoCommand(); - command->setText(i18n("Resize clip start")); - } - - // do this here, too, because otherwise undo won't update the group - if ((item->parentItem() != nullptr) && item->parentItem() != m_selectionGroup) { - new RebuildGroupCommand(this, item->info().track, item->endPos() - GenTime(1, pCore->getCurrentFps()), command); - } - ItemInfo info = item->info(); - if (item->type() == AVWidget) { - bool success = m_timeline->track(oldInfo.track)->resize(oldInfo.startPos.seconds(), (item->startPos() - oldInfo.startPos).seconds(), false); - if (success) { - // Check if there is an automatic transition on that clip (lower track) - Transition *transition = getTransitionItemAtStart(oldInfo.startPos, oldInfo.track); - if ((transition != nullptr) && transition->isAutomatic()) { - ItemInfo trInfo = transition->info(); - ItemInfo newTrInfo = trInfo; - newTrInfo.startPos = item->startPos(); - newTrInfo.cropDuration = trInfo.endPos - newTrInfo.startPos; - if (newTrInfo.startPos < newTrInfo.endPos) { - QDomElement old = transition->toXML(); - if (transition->updateKeyframes(trInfo, newTrInfo)) { - QDomElement xml = transition->toXML(); - m_timeline->transitionHandler->updateTransition(xml.attribute(QStringLiteral("tag")), xml.attribute(QStringLiteral("tag")), - xml.attribute(QStringLiteral("transition_btrack")).toInt(), - xml.attribute(QStringLiteral("transition_atrack")).toInt(), newTrInfo.startPos, - newTrInfo.endPos, xml); - new EditTransitionCommand(this, transition->track(), transition->startPos(), old, xml, false, command); - } - new MoveTransitionCommand(this, trInfo, newTrInfo, true, false, command); - } - } - // Check if there is an automatic transition on that clip (upper track) - transition = getTransitionItemAtStart(oldInfo.startPos, oldInfo.track + 1); - if ((transition != nullptr) && transition->isAutomatic() && transition->transitionEndTrack() == oldInfo.track) { - ItemInfo trInfo = transition->info(); - ItemInfo newTrInfo = trInfo; - newTrInfo.startPos = item->startPos(); - newTrInfo.cropDuration = trInfo.endPos - newTrInfo.startPos; - ClipItem *upperClip = getClipItemAtStart(oldInfo.startPos, oldInfo.track + 1); - // TODO - if ((upperClip == nullptr /*|| !upperClip->baseClip()->isTransparent()*/) && newTrInfo.startPos < newTrInfo.endPos) { - QDomElement old = transition->toXML(); - if (transition->updateKeyframes(trInfo, newTrInfo)) { - QDomElement xml = transition->toXML(); - m_timeline->transitionHandler->updateTransition(xml.attribute(QStringLiteral("tag")), xml.attribute(QStringLiteral("tag")), - xml.attribute(QStringLiteral("transition_btrack")).toInt(), - xml.attribute(QStringLiteral("transition_atrack")).toInt(), newTrInfo.startPos, - newTrInfo.endPos, xml); - new EditTransitionCommand(this, transition->track(), transition->startPos(), old, xml, false, command); - } - new MoveTransitionCommand(this, trInfo, newTrInfo, true, false, command); - } - } - - ClipItem *clip = static_cast(item); - - // Hack: - // Since we must always resize clip before updating the keyframes, we - // put a resize command before & after checking keyframes so that - // we are sure the resize is performed before whenever we do or undo the action - // TODO: find a way to apply adjusteffect after the resize command was done / undone - new ResizeClipCommand(this, oldInfo, info, false, true, command); - adjustEffects(clip, oldInfo, command); - } else { - KdenliveSettings::setSnaptopoints(false); - item->resizeStart((int)oldInfo.startPos.frames(pCore->getCurrentFps())); - KdenliveSettings::setSnaptopoints(snap); - emit displayMessage(i18n("Error when resizing clip"), ErrorMessage); - } - } else if (item->type() == TransitionWidget) { - Transition *transition = static_cast(item); - if (!m_timeline->transitionHandler->moveTransition(transition->transitionTag(), oldInfo.track, oldInfo.track, transition->transitionEndTrack(), - oldInfo.startPos, oldInfo.endPos, info.startPos, info.endPos)) { - // Cannot resize transition - KdenliveSettings::setSnaptopoints(false); - transition->resizeStart((int)oldInfo.startPos.frames(pCore->getCurrentFps())); - KdenliveSettings::setSnaptopoints(snap); - emit displayMessage(i18n("Cannot resize transition"), ErrorMessage); - } else { - QDomElement old = transition->toXML(); - if (transition->updateKeyframes(oldInfo, info)) { - QDomElement xml = transition->toXML(); - m_timeline->transitionHandler->updateTransition(xml.attribute(QStringLiteral("tag")), xml.attribute(QStringLiteral("tag")), - xml.attribute(QStringLiteral("transition_btrack")).toInt(), - xml.attribute(QStringLiteral("transition_atrack")).toInt(), info.startPos, info.endPos, xml); - new EditTransitionCommand(this, transition->track(), transition->startPos(), old, xml, false, command); - } - updateTransitionWidget(transition, info); - new MoveTransitionCommand(this, oldInfo, info, false, true, command); - } - } - if ((item->parentItem() != nullptr) && item->parentItem() != m_selectionGroup) { - new RebuildGroupCommand(this, item->info().track, item->endPos() - GenTime(1, pCore->getCurrentFps()), command); - } - - if (!hasParentCommand) { - m_commandStack->push(command); - } -} - -void CustomTrackView::prepareResizeClipEnd(AbstractClipItem *item, const ItemInfo &oldInfo, int pos, bool check, QUndoCommand *command) -{ - if (pos == oldInfo.endPos.frames(pCore->getCurrentFps())) { - return; - } - bool snap = KdenliveSettings::snaptopoints(); - if (check) { - KdenliveSettings::setSnaptopoints(false); - item->resizeEnd(pos); - if (item->endPos().frames(pCore->getCurrentFps()) != pos) { - item->resizeEnd(oldInfo.endPos.frames(pCore->getCurrentFps())); - emit displayMessage(i18n("Not possible to resize"), ErrorMessage); - KdenliveSettings::setSnaptopoints(snap); - return; - } - KdenliveSettings::setSnaptopoints(snap); - } - - bool hasParentCommand = false; - if (command) { - hasParentCommand = true; - } else { - command = new QUndoCommand(); - } - - // do this here, too, because otherwise undo won't update the group - if ((item->parentItem() != nullptr) && item->parentItem() != m_selectionGroup) { - new RebuildGroupCommand(this, item->info().track, item->startPos(), command); - } - - ItemInfo info = item->info(); - if (item->type() == AVWidget) { - if (!hasParentCommand) { - command->setText(i18n("Resize clip end")); - } - bool success = m_timeline->track(info.track)->resize(oldInfo.startPos.seconds(), (info.endPos - oldInfo.endPos).seconds(), true); - if (success) { - // Check if there is an automatic transition on that clip (lower track) - Transition *tr = getTransitionItemAtEnd(oldInfo.endPos, oldInfo.track); - if ((tr != nullptr) && tr->isAutomatic()) { - ItemInfo trInfo = tr->info(); - ItemInfo newTrInfo = trInfo; - newTrInfo.endPos = item->endPos(); - newTrInfo.cropDuration = newTrInfo.endPos - trInfo.startPos; - if (newTrInfo.endPos > newTrInfo.startPos) { - QDomElement old = tr->toXML(); - if (tr->updateKeyframes(trInfo, newTrInfo)) { - QDomElement xml = tr->toXML(); - m_timeline->transitionHandler->updateTransition(xml.attribute(QStringLiteral("tag")), xml.attribute(QStringLiteral("tag")), - xml.attribute(QStringLiteral("transition_btrack")).toInt(), - xml.attribute(QStringLiteral("transition_atrack")).toInt(), newTrInfo.startPos, - newTrInfo.endPos, xml); - new EditTransitionCommand(this, tr->track(), tr->startPos(), old, xml, false, command); - } - new MoveTransitionCommand(this, trInfo, newTrInfo, true, false, command); - } - } - - // Check if there is an automatic transition on that clip (upper track) - tr = getTransitionItemAtEnd(oldInfo.endPos, oldInfo.track - 1); - if ((tr != nullptr) && tr->isAutomatic() && tr->transitionEndTrack() == oldInfo.track) { - ItemInfo trInfo = tr->info(); - ItemInfo newTrInfo = trInfo; - newTrInfo.endPos = item->endPos(); - newTrInfo.cropDuration = newTrInfo.endPos - trInfo.startPos; - ClipItem *upperClip = getClipItemAtEnd(oldInfo.endPos, oldInfo.track + 1); - // TODO - if ((upperClip == nullptr /*|| !upperClip->baseClip()->isTransparent()*/) && newTrInfo.endPos > newTrInfo.startPos) { - QDomElement old = tr->toXML(); - if (tr->updateKeyframes(trInfo, newTrInfo)) { - QDomElement xml = tr->toXML(); - m_timeline->transitionHandler->updateTransition(xml.attribute(QStringLiteral("tag")), xml.attribute(QStringLiteral("tag")), - xml.attribute(QStringLiteral("transition_btrack")).toInt(), - xml.attribute(QStringLiteral("transition_atrack")).toInt(), newTrInfo.startPos, - newTrInfo.endPos, xml); - new EditTransitionCommand(this, tr->track(), tr->startPos(), old, xml, false, command); - } - new MoveTransitionCommand(this, trInfo, newTrInfo, true, false, command); - } - } - - ClipItem *clip = static_cast(item); - - // Hack: - // Since we must always resize clip before updating the keyframes, we - // put a resize command before & after checking keyframes so that - // we are sure the resize is performed before whenever we do or undo the action - // TODO: find a way to apply adjusteffect after the resize command was done / undone - new ResizeClipCommand(this, oldInfo, info, false, true, command); - adjustEffects(clip, oldInfo, command); - } else { - KdenliveSettings::setSnaptopoints(false); - item->resizeEnd((int)oldInfo.endPos.frames(pCore->getCurrentFps())); - KdenliveSettings::setSnaptopoints(true); - emit displayMessage(i18n("Error when resizing clip"), ErrorMessage); - } - } else if (item->type() == TransitionWidget) { - if (!hasParentCommand) { - command->setText(i18n("Resize transition end")); - } - Transition *transition = static_cast(item); - if (!m_timeline->transitionHandler->moveTransition(transition->transitionTag(), oldInfo.track, oldInfo.track, transition->transitionEndTrack(), - oldInfo.startPos, oldInfo.endPos, info.startPos, info.endPos)) { - // Cannot resize transition - KdenliveSettings::setSnaptopoints(false); - transition->resizeEnd((int)oldInfo.endPos.frames(pCore->getCurrentFps())); - KdenliveSettings::setSnaptopoints(true); - emit displayMessage(i18n("Cannot resize transition"), ErrorMessage); - } else { - // Check transition keyframes - QDomElement old = transition->toXML(); - ItemInfo newInfo = transition->info(); - if (transition->updateKeyframes(oldInfo, newInfo)) { - QDomElement xml = transition->toXML(); - m_timeline->transitionHandler->updateTransition( - xml.attribute(QStringLiteral("tag")), xml.attribute(QStringLiteral("tag")), xml.attribute(QStringLiteral("transition_btrack")).toInt(), - xml.attribute(QStringLiteral("transition_atrack")).toInt(), transition->startPos(), transition->endPos(), xml); - new EditTransitionCommand(this, transition->track(), transition->startPos(), old, xml, false, command); - } - updateTransitionWidget(transition, newInfo); - new MoveTransitionCommand(this, oldInfo, newInfo, false, true, command); - } - } - if ((item->parentItem() != nullptr) && item->parentItem() != m_selectionGroup) { - new RebuildGroupCommand(this, item->info().track, item->startPos(), command); - } - - if (!hasParentCommand) { - updateTrackDuration(oldInfo.track, command); - m_commandStack->push(command); - } -} - -void CustomTrackView::updatePositionEffects(ClipItem *item, const ItemInfo &info, bool standalone) -{ - int effectPos = item->hasEffect(QStringLiteral("volume"), QStringLiteral("fadein")); - if (effectPos != -1) { - QDomElement effect = item->getEffectAtIndex(effectPos); - int start = item->cropStart().frames(pCore->getCurrentFps()); - int duration = EffectsList::parameter(effect, QStringLiteral("out")).toInt() - EffectsList::parameter(effect, QStringLiteral("in")).toInt(); - int max = item->cropDuration().frames(pCore->getCurrentFps()); - if (duration > max) { - // Make sure the fade effect is not longer than the clip - duration = max; - } - duration += start; - EffectsList::setParameter(effect, QStringLiteral("in"), QString::number(start)); - EffectsList::setParameter(effect, QStringLiteral("out"), QString::number(duration)); - if (!m_timeline->track(item->track()) - ->editEffect(item->startPos().seconds(), EffectsController::getEffectArgs(effect), false)) { - emit displayMessage(i18n("Problem editing effect"), ErrorMessage); - } - // if fade effect is displayed, update the effect edit widget with new clip duration - if (standalone && item->isSelected() && effectPos == item->selectedEffectIndex()) { - emit clipItemSelected(item); - } - } - effectPos = item->hasEffect(QStringLiteral("brightness"), QStringLiteral("fade_from_black")); - if (effectPos != -1) { - QDomElement effect = item->getEffectAtIndex(effectPos); - int start = item->cropStart().frames(pCore->getCurrentFps()); - int duration = EffectsList::parameter(effect, QStringLiteral("out")).toInt() - EffectsList::parameter(effect, QStringLiteral("in")).toInt(); - int max = item->cropDuration().frames(pCore->getCurrentFps()); - if (duration > max) { - // Make sure the fade effect is not longer than the clip - duration = max; - } - duration += start; - EffectsList::setParameter(effect, QStringLiteral("in"), QString::number(start)); - EffectsList::setParameter(effect, QStringLiteral("out"), QString::number(duration)); - if (!m_timeline->track(item->track()) - ->editEffect(item->startPos().seconds(), EffectsController::getEffectArgs(effect), false)) { - emit displayMessage(i18n("Problem editing effect"), ErrorMessage); - } - // if fade effect is displayed, update the effect edit widget with new clip duration - if (standalone && item->isSelected() && effectPos == item->selectedEffectIndex()) { - emit clipItemSelected(item); - } - } - - effectPos = item->hasEffect(QStringLiteral("volume"), QStringLiteral("fadeout")); - if (effectPos != -1) { - // there is a fade out effect - QDomElement effect = item->getEffectAtIndex(effectPos); - int max = item->cropDuration().frames(pCore->getCurrentFps()); - int end = max + item->cropStart().frames(pCore->getCurrentFps()) - 1; - int duration = EffectsList::parameter(effect, QStringLiteral("out")).toInt() - EffectsList::parameter(effect, QStringLiteral("in")).toInt(); - if (duration > max) { - // Make sure the fade effect is not longer than the clip - duration = max; - } - int start = end - duration; - EffectsList::setParameter(effect, QStringLiteral("in"), QString::number(start)); - EffectsList::setParameter(effect, QStringLiteral("out"), QString::number(end)); - if (!m_timeline->track(item->track()) - ->editEffect(item->startPos().seconds(), EffectsController::getEffectArgs(effect), false)) { - emit displayMessage(i18n("Problem editing effect"), ErrorMessage); - } - // if fade effect is displayed, update the effect edit widget with new clip duration - if (standalone && item->isSelected() && effectPos == item->selectedEffectIndex()) { - emit clipItemSelected(item); - } - } - - effectPos = item->hasEffect(QStringLiteral("brightness"), QStringLiteral("fade_to_black")); - if (effectPos != -1) { - QDomElement effect = item->getEffectAtIndex(effectPos); - int max = item->cropDuration().frames(pCore->getCurrentFps()); - int end = max + item->cropStart().frames(pCore->getCurrentFps()) - 1; - int duration = EffectsList::parameter(effect, QStringLiteral("out")).toInt() - EffectsList::parameter(effect, QStringLiteral("in")).toInt(); - if (duration > max) { - // Make sure the fade effect is not longer than the clip - duration = max; - } - int start = end - duration; - EffectsList::setParameter(effect, QStringLiteral("in"), QString::number(start)); - EffectsList::setParameter(effect, QStringLiteral("out"), QString::number(end)); - if (!m_timeline->track(item->track()) - ->editEffect(item->startPos().seconds(), EffectsController::getEffectArgs(effect), false)) { - emit displayMessage(i18n("Problem editing effect"), ErrorMessage); - } - // if fade effect is displayed, update the effect edit widget with new clip duration - if (standalone && item->isSelected() && effectPos == item->selectedEffectIndex()) { - emit clipItemSelected(item); - } - } - - effectPos = item->hasEffect(QStringLiteral("freeze"), QStringLiteral("freeze")); - if (effectPos != -1) { - // Freeze effect needs to be adjusted with clip resize - int diff = (info.startPos - item->startPos()).frames(pCore->getCurrentFps()); - QDomElement eff = item->getEffectAtIndex(effectPos); - if (!eff.isNull() && diff != 0) { - int freeze_pos = EffectsList::parameter(eff, QStringLiteral("frame")).toInt() + diff; - EffectsList::setParameter(eff, QStringLiteral("frame"), QString::number(freeze_pos)); - if (standalone && item->isSelected() && item->selectedEffect().attribute(QStringLiteral("id")) == QLatin1String("freeze")) { - emit clipItemSelected(item); - } - } - } -} - -double CustomTrackView::getSnapPointForPos(double pos) -{ - return m_scene->getSnapPointForPos(pos, KdenliveSettings::snaptopoints()); -} - -void CustomTrackView::updateSnapPoints(AbstractClipItem *selected, const QList &offsetList, bool skipSelectedItems) -{ - /* - QList snaps; - if (selected && offsetList.isEmpty()) { - offsetList.append(selected->cropDuration()); - } - QList itemList = items(); - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i) == selected) { - continue; - } - if (skipSelectedItems && itemList.at(i)->isSelected()) { - continue; - } - if (itemList.at(i)->type() == AVWidget) { - ClipItem *item = static_cast (itemList.at(i)); - if (!item) { - continue; - } - GenTime start = item->startPos(); - GenTime end = item->endPos(); - if (!snaps.contains(start)) { - snaps.append(start); - } - if (!snaps.contains(end)) { - snaps.append(end); - } - if (!offsetList.isEmpty()) { - for (int j = 0; j < offsetList.size(); ++j) { - GenTime offset = end - offsetList.at(j); - if (offset > GenTime()) { - if (!snaps.contains(offset)) { - snaps.append(offset); - } - offset = start - offsetList.at(j); - if (offset > GenTime() && !snaps.contains(offset)) { - snaps.append(offset); - } - } - } - } - // Add clip markers - QList markers; - ClipController *controller = m_document->getClipController(item->getBinId()); - if (controller) { - markers = item->snapMarkers(controller->snapMarkers()); - } else { - qWarning("No controller!"); - } - for (int j = 0; j < markers.size(); ++j) { - GenTime t = markers.at(j); - if (!snaps.contains(t)) { - snaps.append(t); - } - if (!offsetList.isEmpty()) { - for (int k = 0; k < offsetList.size(); ++k) { - GenTime offset = t - offsetList.at(k); - if (offset > GenTime() && !snaps.contains(offset)) { - snaps.append(offset); - } - } - } - } - } else if (itemList.at(i)->type() == TransitionWidget) { - Transition *transition = static_cast (itemList.at(i)); - if (!transition) { - continue; - } - GenTime start = transition->startPos(); - GenTime end = transition->endPos(); - if (!snaps.contains(start)) { - snaps.append(start); - } - if (!snaps.contains(end)) { - snaps.append(end); - } - if (!offsetList.isEmpty()) { - for (int j = 0; j < offsetList.size(); ++j) { - GenTime offset = end - offsetList.at(j); - if (offset > GenTime()) { - if (!snaps.contains(offset)) { - snaps.append(offset); - } - offset = start - offsetList.at(j); - if (offset > GenTime() && !snaps.contains(offset)) { - snaps.append(offset); - } - } - } - } - } - } - - // add cursor position - GenTime pos = GenTime(m_cursorPos, pCore->getCurrentFps()); - if (!snaps.contains(pos)) { - snaps.append(pos); - } - if (!offsetList.isEmpty()) { - for (int j = 0; j < offsetList.size(); ++j) { - GenTime offset = pos - offsetList.at(j); - if (!snaps.contains(offset)) { - snaps.append(offset); - } - } - } - - // add guides - for (int i = 0; i < m_guides.count(); ++i) { - GenTime cur_pos = m_guides.at(i)->position(); - if (!snaps.contains(cur_pos)) { - snaps.append(cur_pos); - } - if (!offsetList.isEmpty()) { - for (int j = 0; j < offsetList.size(); ++j) { - GenTime offset = cur_pos - offsetList.at(j); - if (!snaps.contains(offset)) { - snaps.append(offset); - } - } - } - } - - // add render zone - QPoint z = m_document->zone(); - pos = GenTime(z.x(), pCore->getCurrentFps()); - if (!snaps.contains(pos)) { - snaps.append(pos); - } - pos = GenTime(z.y(), pCore->getCurrentFps()); - if (!snaps.contains(pos)) { - snaps.append(pos); - } - - qSort(snaps); - m_scene->setSnapList(snaps); - //for (int i = 0; i < m_snapPoints.size(); ++i) - // //qCDebug(KDENLIVE_LOG) << "SNAP POINT: " << m_snapPoints.at(i).frames(25); - */ -} - -void CustomTrackView::slotSeekToPreviousSnap() -{ - updateSnapPoints(nullptr); - seekCursorPos((int)m_scene->previousSnapPoint(GenTime(m_cursorPos, pCore->getCurrentFps())).frames(pCore->getCurrentFps())); - checkScrolling(); -} - -void CustomTrackView::slotSeekToNextSnap() -{ - updateSnapPoints(nullptr); - seekCursorPos((int)m_scene->nextSnapPoint(GenTime(m_cursorPos, pCore->getCurrentFps())).frames(pCore->getCurrentFps())); - checkScrolling(); -} - -void CustomTrackView::clipStart() -{ - AbstractClipItem *item = getMainActiveClip(); - if (item == nullptr) { - item = m_dragItem; - } - if (item != nullptr) { - seekCursorPos((int)item->startPos().frames(pCore->getCurrentFps())); - checkScrolling(); - } -} - -void CustomTrackView::clipEnd() -{ - AbstractClipItem *item = getMainActiveClip(); - if (item == nullptr) { - item = m_dragItem; - } - if (item != nullptr) { - seekCursorPos((int)item->endPos().frames(pCore->getCurrentFps()) - 1); - checkScrolling(); - } -} - -int CustomTrackView::hasGuide(double pos, bool framePos) -{ - for (int i = 0; i < m_guides.count(); ++i) { - double guidePos = m_guides.at(i)->position().frames(pCore->getCurrentFps()) * (framePos ? 1 : matrix().m11()); - if (framePos) { - if (guidePos == pos) { - return guidePos; - } - } else { - if (qAbs(guidePos - pos) <= QApplication::startDragDistance()) { - return guidePos; - } - } - if (guidePos > pos) { - return -1; - } - } - return -1; -} - -void CustomTrackView::buildGuidesMenu(QMenu *goMenu) const -{ - goMenu->clear(); - double fps = pCore->getCurrentFps(); - for (int i = 0; i < m_guides.count(); ++i) { - QAction *act = goMenu->addAction(m_guides.at(i)->label() + QLatin1Char('/') + Timecode::getStringTimecode(m_guides.at(i)->position().frames(fps), fps)); - act->setData(m_guides.at(i)->position().frames(pCore->getCurrentFps())); - } - goMenu->setEnabled(!m_guides.isEmpty()); -} - -QMap CustomTrackView::guidesData() const -{ - QMap gData; - for (int i = 0; i < m_guides.count(); ++i) { - gData.insert(m_guides.at(i)->position().seconds(), m_guides.at(i)->label()); - } - return gData; -} - -void CustomTrackView::editGuide(const GenTime &oldPos, const GenTime &pos, const QString &comment) -{ - if (comment.isEmpty() && pos < GenTime()) { - // Delete guide - bool found = false; - for (int i = 0; i < m_guides.count(); ++i) { - if (m_guides.at(i)->position() == oldPos) { - delete m_guides.takeAt(i); - found = true; - break; - } - } - if (!found) { - emit displayMessage(i18n("No guide at cursor time"), ErrorMessage); - } - } else if (oldPos >= GenTime()) { - // move guide - for (int i = 0; i < m_guides.count(); ++i) { - if (m_guides.at(i)->position() == oldPos) { - Guide *item = m_guides.at(i); - item->updateGuide(pos, comment); - break; - } - } - } else { - addGuide(pos, comment); - } - qSort(m_guides.begin(), m_guides.end(), sortGuidesList); - emit guidesUpdated(); -} - -bool CustomTrackView::addGuide(const GenTime &pos, const QString &comment, bool loadingProject) -{ - for (int i = 0; i < m_guides.count(); ++i) { - if (m_guides.at(i)->position() == pos) { - emit displayMessage(i18n("A guide already exists at position %1", m_document->timecode().getTimecodeFromFrames(pos.frames(pCore->getCurrentFps()))), - ErrorMessage); - return false; - } - } - auto *g = new Guide(this, pos, comment, m_tracksHeight * m_timeline->visibleTracksCount() * matrix().m22()); - scene()->addItem(g); - m_guides.append(g); - qSort(m_guides.begin(), m_guides.end(), sortGuidesList); - if (!loadingProject) { - emit guidesUpdated(); - } - return true; -} - -void CustomTrackView::slotAddGuide(bool dialog) -{ - /* - CommentedTime marker(GenTime(m_cursorPos, pCore->getCurrentFps()), i18n("Guide")); - if (dialog) { - QPointer d = new MarkerDialog(nullptr, marker, m_document->timecode(), i18n("Add Guide"), this); - if (d->exec() != QDialog::Accepted) { - delete d; - return; - } - marker = d->newMarker(); - delete d; - } else { - marker.setComment(m_document->timecode().getDisplayTimecodeFromFrames(m_cursorPos, false)); - } - if (addGuide(marker.time(), marker.comment())) { - EditGuideCommand *command = new EditGuideCommand(this, GenTime(), QString(), marker.time(), marker.comment(), false); - m_commandStack->push(command); - } - */ -} - -void CustomTrackView::slotEditGuide(int guidePos, const QString &newText) -{ - /* - GenTime pos; - if (guidePos == -1) { - pos = GenTime(m_cursorPos, pCore->getCurrentFps()); - } else { - pos = GenTime(guidePos, pCore->getCurrentFps()); - } - bool found = false; - for (int i = 0; i < m_guides.count(); ++i) { - if (m_guides.at(i)->position() == pos) { - CommentedTime guide = m_guides.at(i)->info(); - if (!newText.isEmpty()) { - EditGuideCommand *command = new EditGuideCommand(this, guide.time(), guide.comment(), guide.time(), newText, true); - m_commandStack->push(command); - } else { - slotEditGuide(guide); - } - found = true; - break; - } - } - if (!found) { - emit displayMessage(i18n("No guide at cursor time"), ErrorMessage); - } - */ -} - -void CustomTrackView::slotEditGuide(const CommentedTime &guide) -{ - /* - QPointer d = new MarkerDialog(nullptr, guide, m_document->timecode(), i18n("Edit Guide"), this); - if (d->exec() == QDialog::Accepted) { - EditGuideCommand *command = new EditGuideCommand(this, guide.time(), guide.comment(), d->newMarker().time(), d->newMarker().comment(), true); - m_commandStack->push(command); - } - delete d; - */ -} - -void CustomTrackView::slotEditTimeLineGuide() -{ - /* - if (m_dragGuide == nullptr) { - return; - } - CommentedTime guide = m_dragGuide->info(); - QPointer d = new MarkerDialog(nullptr, guide, m_document->timecode(), i18n("Edit Guide"), this); - if (d->exec() == QDialog::Accepted) { - EditGuideCommand *command = new EditGuideCommand(this, guide.time(), guide.comment(), d->newMarker().time(), d->newMarker().comment(), true); - m_commandStack->push(command); - } - delete d; - */ -} - -void CustomTrackView::slotDeleteGuide(int guidePos) -{ - GenTime pos; - if (guidePos == -1) { - pos = GenTime(m_cursorPos, pCore->getCurrentFps()); - } else { - pos = GenTime(guidePos, pCore->getCurrentFps()); - } - bool found = false; - for (int i = 0; i < m_guides.count(); ++i) { - if (m_guides.at(i)->position() == pos) { - EditGuideCommand *command = new EditGuideCommand(this, m_guides.at(i)->position(), m_guides.at(i)->label(), GenTime(-1), QString(), true); - m_commandStack->push(command); - found = true; - break; - } - } - if (!found) { - emit displayMessage(i18n("No guide at cursor time"), ErrorMessage); - } -} - -void CustomTrackView::slotDeleteTimeLineGuide() -{ - if (m_dragGuide == nullptr) { - return; - } - EditGuideCommand *command = new EditGuideCommand(this, m_dragGuide->position(), m_dragGuide->label(), GenTime(-1), QString(), true); - m_commandStack->push(command); -} - -void CustomTrackView::slotDeleteAllGuides() -{ - auto *deleteAll = new QUndoCommand(); - deleteAll->setText(QStringLiteral("Delete all guides")); - for (int i = 0; i < m_guides.count(); ++i) { - new EditGuideCommand(this, m_guides.at(i)->position(), m_guides.at(i)->label(), GenTime(-1), QString(), true, deleteAll); - } - m_commandStack->push(deleteAll); -} - -void CustomTrackView::setTool(ProjectTool tool) -{ - if (m_tool == tool) { - return; - } - m_tool = tool; - m_currentToolManager->closeTool(); - switch (m_tool) { - case RazorTool: - m_currentToolManager = m_toolManagers.value(AbstractToolManager::RazorType); - break; - case SpacerTool: - m_currentToolManager = m_toolManagers.value(AbstractToolManager::SpacerType); - break; - default: - m_currentToolManager = m_toolManagers.value(AbstractToolManager::SelectType); - } - m_currentToolManager->initTool(m_tracksHeight * m_scene->scale().y()); -} - -void CustomTrackView::setScale(double scaleFactor, double verticalScale, bool zoomOnMouse) -{ - - QMatrix newmatrix; - int lastMousePos = getMousePos(); - newmatrix = newmatrix.scale(scaleFactor, verticalScale); - m_scene->isZooming = true; - m_scene->setScale(scaleFactor, verticalScale); - removeTipAnimation(); - bool adjust = verticalScale != matrix().m22(); - setMatrix(newmatrix); - double newHeight = m_tracksHeight * m_timeline->visibleTracksCount() * matrix().m22(); - if (adjust) { - setSceneRect(0, 0, sceneRect().width(), m_tracksHeight * m_timeline->visibleTracksCount()); - for (int i = 0; i < m_guides.count(); ++i) { - m_guides.at(i)->setLine(0, 0, 0, newHeight - 1); - } - } - if (scaleFactor < 1.5) { - m_cursorLine->setFlag(QGraphicsItem::ItemIgnoresTransformations, true); - QPen p = m_cursorLine->pen(); - QColor c = p.color(); - c.setAlpha(255); - p.setColor(c); - m_cursorLine->setPen(p); - m_cursorOffset = 0; - m_cursorLine->setLine(0, 0, 0, newHeight - 1); - } else { - m_cursorLine->setFlag(QGraphicsItem::ItemIgnoresTransformations, false); - QPen p = m_cursorLine->pen(); - QColor c = p.color(); - c.setAlpha(100); - p.setColor(c); - m_cursorLine->setPen(p); - m_cursorOffset = 0.5; - m_cursorLine->setLine(0, 0, 0, m_tracksHeight * m_timeline->visibleTracksCount() - 1); - } - - int diff = sceneRect().width() - m_projectDuration; - if (diff * newmatrix.m11() < 50) { - if (newmatrix.m11() < 0.4) { - setSceneRect(0, 0, (m_projectDuration + 100 / newmatrix.m11()), sceneRect().height()); - } else { - setSceneRect(0, 0, (m_projectDuration + 300), sceneRect().height()); - } - } - double verticalPos = mapToScene(QPoint(0, viewport()->height() / 2)).y(); - if (zoomOnMouse) { - // Zoom on mouse position - centerOn(QPointF(lastMousePos, verticalPos)); - int cur_diff = scaleFactor * (getMousePos() - lastMousePos); - horizontalScrollBar()->setValue(horizontalScrollBar()->value() - cur_diff); - } else { - centerOn(QPointF(cursorPos(), verticalPos)); - } - m_currentToolManager->updateTimelineItems(); - m_scene->isZooming = false; -} - -void CustomTrackView::slotRefreshGuides() -{ - if (KdenliveSettings::showmarkers()) { - for (int i = 0; i < m_guides.count(); ++i) { - m_guides.at(i)->update(); - } - } -} - -void CustomTrackView::drawBackground(QPainter *painter, const QRectF &rect) -{ - // TODO: optimize, we currently redraw bg on every cursor move - painter->setClipRect(rect); - QPen pen1 = painter->pen(); - QColor lineColor = palette().text().color(); - lineColor.setAlpha(50); - pen1.setColor(lineColor); - painter->setPen(pen1); - double min = rect.left(); - double max = rect.right(); - // painter->drawLine(QPointF(min, 0), QPointF(max, 0)); - int maxTrack = m_timeline->visibleTracksCount(); - QColor audioColor = palette().alternateBase().color(); - QColor activeLockColor = m_lockedTrackColor; - activeLockColor.setAlpha(90); - for (int i = 1; i <= maxTrack; ++i) { - TrackInfo info = m_timeline->getTrackInfo(i); - if (info.isLocked || info.type == AudioTrack || i == m_selectedTrack) { - const QRectF track(min, m_tracksHeight * (maxTrack - i), max - min, m_tracksHeight - 1); - if (i == m_selectedTrack) { - painter->fillRect(track, info.isLocked ? activeLockColor : m_selectedTrackColor); - } else { - painter->fillRect(track, info.isLocked ? m_lockedTrackColor : audioColor); - } - } - painter->drawLine(QPointF(min, m_tracksHeight * (maxTrack - i) - 1), QPointF(max, m_tracksHeight * (maxTrack - i) - 1)); - } - painter->drawLine(QPointF(min, m_tracksHeight * (maxTrack)-1), QPointF(max, m_tracksHeight * (maxTrack)-1)); -} - -bool CustomTrackView::findString(const QString &text) -{ - QString marker; - for (int i = 0; i < m_searchPoints.size(); ++i) { - marker = m_searchPoints.at(i).comment(); - if (marker.contains(text, Qt::CaseInsensitive)) { - seekCursorPos(m_searchPoints.at(i).time().frames(pCore->getCurrentFps())); - int vert = verticalScrollBar()->value(); - int hor = cursorPos(); - ensureVisible(hor, vert + 10, 2, 2, 50, 0); - m_findIndex = i; - return true; - } - } - return false; -} - -void CustomTrackView::selectFound(const QString &track, const QString &pos) -{ - int hor = m_document->timecode().getFrameCount(pos); - activateMonitor(); - seekCursorPos(hor); - slotSelectTrack(track.toInt()); - selectClip(true, false, track.toInt(), hor); - ensureVisible(hor, verticalScrollBar()->value() + 10, 2, 2, 50, 0); -} - -bool CustomTrackView::findNextString(const QString &text) -{ - QString marker; - for (int i = m_findIndex + 1; i < m_searchPoints.size(); ++i) { - marker = m_searchPoints.at(i).comment(); - if (marker.contains(text, Qt::CaseInsensitive)) { - seekCursorPos(m_searchPoints.at(i).time().frames(pCore->getCurrentFps())); - int vert = verticalScrollBar()->value(); - int hor = cursorPos(); - ensureVisible(hor, vert + 10, 2, 2, 50, 0); - m_findIndex = i; - return true; - } - } - m_findIndex = -1; - return false; -} - -void CustomTrackView::initSearchStrings() -{ - /* - m_searchPoints.clear(); - QList itemList = items(); - for (int i = 0; i < itemList.count(); ++i) { - // parse all clip names - if (itemList.at(i)->type() == AVWidget) { - ClipItem *item = static_cast (itemList.at(i)); - GenTime start = item->startPos(); - CommentedTime t(start, item->clipName()); - m_searchPoints.append(t); - // add all clip markers - ClipController *controller = m_document->getClipController(item->getBinId()); - QList< CommentedTime > markers = controller->commentedSnapMarkers(); - m_searchPoints += markers; - } - } - - // add guides - for (int i = 0; i < m_guides.count(); ++i) { - m_searchPoints.append(m_guides.at(i)->info()); - } - - qSort(m_searchPoints); - */ -} - -void CustomTrackView::clearSearchStrings() -{ - m_searchPoints.clear(); - m_findIndex = 0; -} - -QList CustomTrackView::findId(const QString &clipId) -{ - QList matchingInfo; - QList itemList = items(); - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget) { - ClipItem *item = static_cast(itemList.at(i)); - if (item->getBinId() == clipId) { - matchingInfo << item->info(); - } - } - } - return matchingInfo; -} - -void CustomTrackView::copyClip() -{ - qDeleteAll(m_copiedItems); - m_copiedItems.clear(); - QAction *pasteAction = m_document->getAction(KStandardAction::name(KStandardAction::Paste)); - QList itemList = scene()->selectedItems(); - if (itemList.isEmpty()) { - emit displayMessage(i18n("Select a clip before copying"), ErrorMessage); - if (pasteAction) { - pasteAction->setEnabled(false); - } - return; - } - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget) { - ClipItem *clip = static_cast(itemList.at(i)); - ClipItem *clone = clip->clone(clip->info()); - m_copiedItems.append(clone); - } else if (itemList.at(i)->type() == TransitionWidget) { - Transition *dup = static_cast(itemList.at(i)); - m_copiedItems.append(dup->clone()); - } - } - if (pasteAction) { - pasteAction->setEnabled(!m_copiedItems.isEmpty()); - } -} - -bool CustomTrackView::canBePastedTo(const ItemInfo &info, int type, const QList &excluded) const -{ - if (m_scene->editMode() != TimelineMode::NormalEdit) { - // If we are in overwrite mode, always allow the move - return true; - } - int height = m_tracksHeight - 2; - int offset = 0; - if (type == TransitionWidget) { - height = Transition::itemHeight(); - offset = Transition::itemOffset(); - } else if (type == AVWidget) { - height = ClipItem::itemHeight(); - offset = ClipItem::itemOffset(); - } - QRectF rect((double)info.startPos.frames(pCore->getCurrentFps()), (double)(getPositionFromTrack(info.track) + 1 + offset), - (double)(info.endPos - info.startPos).frames(pCore->getCurrentFps()), (double)height); - QList collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect); - for (int i = 0; i < collisions.count(); ++i) { - if (collisions.at(i)->type() == type && !excluded.contains((AbstractClipItem *)collisions.at(i))) { - return false; - } - } - return true; -} - -bool CustomTrackView::canBePastedTo(const QList &infoList, int type) const -{ - QPainterPath path; - for (int i = 0; i < infoList.count(); ++i) { - const QRectF rect((double)infoList.at(i).startPos.frames(pCore->getCurrentFps()), (double)(getPositionFromTrack(infoList.at(i).track) + 1), - (double)(infoList.at(i).endPos - infoList.at(i).startPos).frames(pCore->getCurrentFps()), (double)(m_tracksHeight - 1)); - path.addRect(rect); - } - QList collisions = scene()->items(path); - for (int i = 0; i < collisions.count(); ++i) { - if (collisions.at(i)->type() == type) { - return false; - } - } - return true; -} - -bool CustomTrackView::canBePasted(const QList &items, GenTime offset, int trackOffset, QList excluded) const -{ - excluded << items; - for (int i = 0; i < items.count(); ++i) { - ItemInfo info = items.at(i)->info(); - info.startPos += offset; - info.endPos += offset; - info.track += trackOffset; - if (!canBePastedTo(info, items.at(i)->type(), excluded)) { - return false; - } - } - return true; -} - -void CustomTrackView::pasteClip() -{ - if (m_copiedItems.isEmpty()) { - emit displayMessage(i18n("No clip copied"), ErrorMessage); - return; - } - QPoint position; - int track = -1; - GenTime pos = GenTime(-1); - if (m_menuPosition.isNull()) { - position = mapFromGlobal(QCursor::pos()); - if (!contentsRect().contains(position)) { - track = m_selectedTrack; - pos = GenTime(m_cursorPos, pCore->getCurrentFps()); - /*emit displayMessage(i18n("Cannot paste selected clips"), ErrorMessage); - return;*/ - } - } else { - position = m_menuPosition; - } - - if (pos == GenTime(-1)) { - pos = GenTime((int)(mapToScene(position).x()), pCore->getCurrentFps()); - } - if (track == -1) { - track = getTrackFromPos(mapToScene(position).y()); - } - - GenTime leftPos = m_copiedItems.at(0)->startPos(); - int lowerTrack = m_copiedItems.at(0)->track(); - int upperTrack = m_copiedItems.at(0)->track(); - for (int i = 1; i < m_copiedItems.count(); ++i) { - if (m_copiedItems.at(i)->startPos() < leftPos) { - leftPos = m_copiedItems.at(i)->startPos(); - } - if (m_copiedItems.at(i)->track() < lowerTrack) { - lowerTrack = m_copiedItems.at(i)->track(); - } - if (m_copiedItems.at(i)->track() > upperTrack) { - upperTrack = m_copiedItems.at(i)->track(); - } - } - - GenTime offset = pos - leftPos; - int trackOffset = track - lowerTrack; - if (upperTrack + trackOffset > m_timeline->tracksCount() - 1) { - trackOffset = m_timeline->tracksCount() - 1 - upperTrack; - } - if (lowerTrack + trackOffset < 0 || !canBePasted(m_copiedItems, offset, trackOffset)) { - emit displayMessage(i18n("Cannot paste selected clips"), ErrorMessage); - return; - } - auto *pasteClips = new QUndoCommand(); - pasteClips->setText(QStringLiteral("Paste clips")); - RefreshMonitorCommand *firstRefresh = new RefreshMonitorCommand(this, ItemInfo(), false, true, pasteClips); - QList range; - for (int i = 0; i < m_copiedItems.count(); ++i) { - // parse all clip names - if ((m_copiedItems.at(i) != nullptr) && m_copiedItems.at(i)->type() == AVWidget) { - ClipItem *clip = static_cast(m_copiedItems.at(i)); - ItemInfo info = clip->info(); - info.startPos += offset; - info.endPos += offset; - info.track += trackOffset; - if (canBePastedTo(info, AVWidget)) { - new AddTimelineClipCommand(this, clip->getBinId(), info, clip->effectList(), clip->clipState(), true, false, false, pasteClips); - if (clip->hasVisibleVideo()) { - range << info; - } - } else { - emit displayMessage(i18n("Cannot paste clip to selected place"), ErrorMessage); - } - } else if ((m_copiedItems.at(i) != nullptr) && m_copiedItems.at(i)->type() == TransitionWidget) { - Transition *tr = static_cast(m_copiedItems.at(i)); - ItemInfo info; - info.startPos = tr->startPos() + offset; - info.endPos = tr->endPos() + offset; - info.track = tr->track() + trackOffset; - int transitionEndTrack; - if (!tr->forcedTrack()) { - transitionEndTrack = getPreviousVideoTrack(info.track); - } else { - transitionEndTrack = tr->transitionEndTrack(); - } - if (canBePastedTo(info, TransitionWidget)) { - if (info.startPos >= info.endPos) { - emit displayMessage(i18n("Invalid transition"), ErrorMessage); - } else { - new AddTransitionCommand(this, info, transitionEndTrack, tr->toXML(), false, true, pasteClips); - range << info; - } - } else { - emit displayMessage(i18n("Cannot paste transition to selected place"), ErrorMessage); - } - } - } - updateTrackDuration(-1, pasteClips); - firstRefresh->updateRange(range); - new RefreshMonitorCommand(this, range, true, false, pasteClips); - m_commandStack->push(pasteClips); -} - -void CustomTrackView::pasteClipEffects() -{ - if (m_copiedItems.count() != 1 || m_copiedItems.at(0)->type() != AVWidget) { - emit displayMessage(i18n("You must copy exactly one clip before pasting effects"), ErrorMessage); - return; - } - ClipItem *clip = static_cast(m_copiedItems.at(0)); - - auto *paste = new QUndoCommand(); - paste->setText(QStringLiteral("Paste effects")); - - QList clips = scene()->selectedItems(); - - // expand groups - for (int i = 0; i < clips.count(); ++i) { - if (clips.at(i)->type() == GroupWidget) { - QList children = clips.at(i)->childItems(); - for (int j = 0; j < children.count(); ++j) { - if (children.at(j)->type() == AVWidget && !clips.contains(children.at(j))) { - clips.append(children.at(j)); - } - } - } - } - - for (int i = 0; i < clips.count(); ++i) { - if (clips.at(i)->type() == AVWidget) { - ClipItem *item = static_cast(clips.at(i)); - for (int j = 0; j < clip->effectsCount(); ++j) { - QDomElement eff = clip->effect(j); - if (eff.attribute(QStringLiteral("unique"), QStringLiteral("0")) == QLatin1String("0") || - item->hasEffect(eff.attribute(QStringLiteral("tag")), eff.attribute(QStringLiteral("id"))) == -1) { - adjustKeyfames(clip->cropStart(), item->cropStart(), item->cropDuration(), eff); - new AddEffectCommand(this, item->track(), item->startPos(), eff, true, paste); - } - } - } - } - if (paste->childCount() > 0) { - m_commandStack->push(paste); - } else { - delete paste; - } - - // adjust effects (fades, ...) - for (int i = 0; i < clips.count(); ++i) { - if (clips.at(i)->type() == AVWidget) { - ClipItem *item = static_cast(clips.at(i)); - updatePositionEffects(item, item->info()); - } - } -} - -void CustomTrackView::adjustKeyfames(GenTime oldstart, GenTime newstart, GenTime duration, QDomElement xml) -{ - // parse parameters to check if we need to adjust to the new crop start - QDomNodeList params = xml.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - if (e.isNull()) { - continue; - } - if (e.attribute(QStringLiteral("type")) == QLatin1String("keyframe") || e.attribute(QStringLiteral("type")) == QLatin1String("simplekeyframe")) { - // Effect has a keyframe type parameter, we need to adjust the values - QString adjusted = EffectsController::adjustKeyframes(e.attribute(QStringLiteral("keyframes")), oldstart.frames(pCore->getCurrentFps()), - newstart.frames(pCore->getCurrentFps()), - (newstart + duration).frames(pCore->getCurrentFps()) - 1); - e.setAttribute(QStringLiteral("keyframes"), adjusted); - } else if (e.attribute(QStringLiteral("type")) == QLatin1String("animated")) { - if (xml.attribute(QStringLiteral("kdenlive:sync_in_out")) != QLatin1String("1")) { - QString resizedAnim = KeyframeView::cutAnimation(e.attribute(QStringLiteral("value")), 0, duration.frames(pCore->getCurrentFps()), - duration.frames(pCore->getCurrentFps())); - e.setAttribute(QStringLiteral("value"), resizedAnim); - } else if (xml.hasAttribute(QStringLiteral("kdenlive:sync_in_out"))) { - // Effect attached to clip in, update - xml.setAttribute(QStringLiteral("in"), QString::number(newstart.frames(pCore->getCurrentFps()))); - xml.setAttribute(QStringLiteral("out"), QString::number((newstart + duration).frames(pCore->getCurrentFps()))); - } - } - } -} - -ClipItem *CustomTrackView::getClipUnderCursor() const -{ - QRectF rect((double)seekPosition(), 0.0, 1.0, (double)(m_tracksHeight * m_timeline->visibleTracksCount())); - QList collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect); - if ((m_dragItem != nullptr) && !collisions.isEmpty() && collisions.contains(m_dragItem) && m_dragItem->type() == AVWidget && !m_dragItem->isItemLocked()) { - return static_cast(m_dragItem); - } - for (int i = 0; i < collisions.count(); ++i) { - if (collisions.at(i)->type() == AVWidget) { - ClipItem *clip = static_cast(collisions.at(i)); - if (!clip->isItemLocked()) { - return clip; - } - } - } - return nullptr; -} - -const QString CustomTrackView::getClipUnderCursor(int *pos, QPoint *zone) const -{ - ClipItem *item = static_cast(getMainActiveClip()); - if (item == nullptr) { - if ((m_dragItem != nullptr) && m_dragItem->type() == AVWidget) { - item = static_cast(m_dragItem); - } - } else { - *pos = seekPosition() - (item->startPos() - item->cropStart()).frames(pCore->getCurrentFps()); - if (zone) { - *zone = QPoint(item->cropStart().frames(pCore->getCurrentFps()), (item->cropStart() + item->cropDuration()).frames(pCore->getCurrentFps())); - } - } - QString result; - if (item) { - result = item->getBinId(); - } - return result; -} - -AbstractClipItem *CustomTrackView::getMainActiveClip() const -{ - QList clips = scene()->selectedItems(); - if (clips.isEmpty()) { - return getClipUnderCursor(); - } - AbstractClipItem *item = nullptr; - for (int i = 0; i < clips.count(); ++i) { - if (clips.at(i)->type() == AVWidget) { - item = static_cast(clips.at(i)); - if (clips.count() > 1 && item->startPos().frames(pCore->getCurrentFps()) <= seekPosition() && - item->endPos().frames(pCore->getCurrentFps()) >= seekPosition()) { - break; - } - } - } - if (item) { - return item; - } - - return nullptr; -} - -ClipItem *CustomTrackView::getActiveClipUnderCursor(bool allowOutsideCursor) const -{ - QList clips = scene()->selectedItems(); - if (clips.isEmpty()) { - return getClipUnderCursor(); - } - ClipItem *item; - // remove all items in the list that are not clips - for (int i = 0; i < clips.count();) { - if (clips.at(i)->type() != AVWidget) { - clips.removeAt(i); - } else { - ++i; - } - } - if (clips.count() == 1 && allowOutsideCursor) { - return static_cast(clips.at(0)); - } - for (int i = 0; i < clips.count(); ++i) { - if (clips.at(i)->type() == AVWidget) { - item = static_cast(clips.at(i)); - if (item->startPos().frames(pCore->getCurrentFps()) <= seekPosition() && item->endPos().frames(pCore->getCurrentFps()) >= seekPosition()) { - return item; - } - } - } - - return nullptr; -} - -void CustomTrackView::expandActiveClip() -{ - AbstractClipItem *item = getActiveClipUnderCursor(true); - if (item == nullptr || item->type() != AVWidget) { - emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage); - return; - } - ClipItem *clip = static_cast(item); - const QString url = clip->binClip()->url(); - if (clip->clipType() != Playlist || url.isEmpty()) { - emit displayMessage(i18n("You must select a playlist clip for this action"), ErrorMessage); - return; - } - // Step 1: remove playlist clip - auto *expandCommand = new QUndoCommand(); - expandCommand->setText(i18n("Expand Clip")); - ItemInfo info = clip->info(); - new AddTimelineClipCommand(this, clip->getBinId(), info, clip->effectList(), clip->clipState(), true, true, true, expandCommand); - emit importPlaylistClips(info, url, expandCommand); -} - -void CustomTrackView::setInPoint() -{ - AbstractClipItem *clip = getActiveClipUnderCursor(true); - if (clip == nullptr) { - if ((m_dragItem != nullptr) && m_dragItem->type() == TransitionWidget) { - clip = m_dragItem; - } else { - emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage); - return; - } - } - - AbstractGroupItem *parent = static_cast(clip->parentItem()); - if (parent) { - // Resizing a group - auto *resizeCommand = new QUndoCommand(); - resizeCommand->setText(i18n("Resize group")); - QList items = parent->childItems(); - GenTime min = parent->startPos(); - GenTime max = min; - for (int i = 0; i < items.count(); ++i) { - AbstractClipItem *item = static_cast(items.at(i)); - if ((item != nullptr) && item->type() == AVWidget) { - ItemInfo info = item->info(); - prepareResizeClipStart(item, info, seekPosition(), true, resizeCommand); - ClipItem *cp = qobject_cast(clip); - if ((cp != nullptr) && cp->hasVisibleVideo()) { - min = qMin(min, item->startPos()); - max = qMax(max, item->startPos()); - } - } - } - if (resizeCommand->childCount() > 0) { - m_commandStack->push(resizeCommand); - if (min < max) { - ItemInfo nfo; - nfo.startPos = min; - nfo.endPos = max; - monitorRefresh(nfo, true); - } - } else { - // TODO warn user of failed resize - delete resizeCommand; - } - } else { - ItemInfo info = clip->info(); - prepareResizeClipStart(clip, info, seekPosition(), true); - ClipItem *cp = qobject_cast(clip); - if ((cp != nullptr) && cp->hasVisibleVideo()) { - ItemInfo updated = cp->info(); - if (updated.startPos > info.startPos) { - updated.endPos = updated.startPos; - updated.startPos = info.startPos; - } else { - updated.endPos = info.startPos; - } - monitorRefresh(updated, true); - } - } -} - -void CustomTrackView::setOutPoint() -{ - AbstractClipItem *clip = getActiveClipUnderCursor(true); - if (clip == nullptr) { - if ((m_dragItem != nullptr) && m_dragItem->type() == TransitionWidget) { - clip = m_dragItem; - } else { - emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage); - return; - } - } - AbstractGroupItem *parent = static_cast(clip->parentItem()); - if (parent) { - // Resizing a group - auto *resizeCommand = new QUndoCommand(); - resizeCommand->setText(i18n("Resize group")); - QList items = parent->childItems(); - GenTime min = parent->startPos() + parent->duration(); - GenTime max = min; - for (int i = 0; i < items.count(); ++i) { - AbstractClipItem *item = static_cast(items.at(i)); - if ((item != nullptr) && item->type() == AVWidget) { - ItemInfo info = item->info(); - prepareResizeClipEnd(item, info, seekPosition(), true, resizeCommand); - ClipItem *cp = qobject_cast(item); - if ((cp != nullptr) && cp->hasVisibleVideo()) { - min = qMin(min, item->endPos()); - max = qMax(max, item->endPos()); - } - } - } - if (resizeCommand->childCount() > 0) { - m_commandStack->push(resizeCommand); - if (min < max) { - ItemInfo nfo; - nfo.startPos = min; - nfo.endPos = max; - monitorRefresh(nfo, true); - } - } else { - // TODO warn user of failed resize - delete resizeCommand; - } - } else { - ItemInfo info = clip->info(); - prepareResizeClipEnd(clip, info, seekPosition(), true); - ClipItem *cp = qobject_cast(clip); - if ((cp != nullptr) && cp->hasVisibleVideo()) { - ItemInfo updated = cp->info(); - if (updated.endPos > info.endPos) { - updated.startPos = info.endPos; - } else { - updated.startPos = updated.endPos; - updated.endPos = info.endPos; - } - monitorRefresh(updated, true); - } - } -} - -void CustomTrackView::slotUpdateAllThumbs() -{ - if (!isEnabled()) { - return; - } - QList itemList = scene()->items(); - // if (itemList.isEmpty()) return; - ClipItem *item; - bool ok = false; - QDir thumbsFolder = m_document->getCacheDir(CacheThumbs, &ok); - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget) { - item = static_cast(itemList.at(i)); - if ((item != nullptr) && item->isEnabled() && item->clipType() != Color && item->clipType() != Audio) { - // Check if we have a cached thumbnail - if (item->clipType() == Image || item->clipType() == Text) { - QString thumb = thumbsFolder.absoluteFilePath(item->getBinHash() + QStringLiteral("#0.png")); - if (ok && QFile::exists(thumb)) { - QPixmap pix(thumb); - if (pix.isNull()) { - QFile::remove(thumb); - } - item->slotSetStartThumb(pix); - } - } else { - QString startThumb = thumbsFolder.absoluteFilePath(item->getBinHash() + QLatin1Char('#')); - QString endThumb = startThumb; - startThumb.append(QString::number((int)item->speedIndependantCropStart().frames(pCore->getCurrentFps())) + QStringLiteral(".png")); - endThumb.append( - QString::number((int)(item->speedIndependantCropStart() + item->speedIndependantCropDuration()).frames(pCore->getCurrentFps()) - 1) + - QStringLiteral(".png")); - if (QFile::exists(startThumb)) { - QPixmap pix(startThumb); - if (pix.isNull()) { - QFile::remove(startThumb); - } - item->slotSetStartThumb(pix); - } - if (QFile::exists(endThumb)) { - QPixmap pix(endThumb); - if (pix.isNull()) { - QFile::remove(endThumb); - } - item->slotSetEndThumb(pix); - } - } - item->refreshClip(false, false); - } - } - } - viewport()->update(); -} - -void CustomTrackView::saveThumbnails() -{ - QList itemList = scene()->items(); - ClipItem *item; - bool ok = false; - QDir thumbsFolder = m_document->getCacheDir(CacheThumbs, &ok); - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == AVWidget) { - item = static_cast(itemList.at(i)); - if (item->clipType() != Color && item->clipType() != Audio) { - // Check if we have a cached thumbnail - if (item->clipType() == Image || item->clipType() == Text || item->clipType() == Audio) { - QString thumb = thumbsFolder.absoluteFilePath(item->getBinHash() + QStringLiteral("#0.png")); - if (!QFile::exists(thumb)) { - item->startThumb().save(thumb); - } - } else { - QString startThumb = thumbsFolder.absoluteFilePath(item->getBinHash() + QLatin1Char('#')); - QString endThumb = startThumb; - startThumb.append(QString::number((int)item->speedIndependantCropStart().frames(pCore->getCurrentFps())) + QStringLiteral(".png")); - endThumb.append( - QString::number((int)(item->speedIndependantCropStart() + item->speedIndependantCropDuration()).frames(pCore->getCurrentFps()) - 1) + - QStringLiteral(".png")); - if (!QFile::exists(startThumb)) { - item->startThumb().save(startThumb); - } - if (!QFile::exists(endThumb)) { - item->endThumb().save(endThumb); - } - } - } - } - } -} - -void CustomTrackView::slotInsertTrack(int ix) -{ - QPointer d = new TrackDialog(m_timeline, parentWidget()); - d->comboTracks->setCurrentIndex(m_timeline->visibleTracksCount() - ix); - d->label->setText(i18n("Insert track")); - QStringList existingTrackNames = m_timeline->getTrackNames(); - int i = 1; - QString proposedName = i18n("Video %1", i); - while (existingTrackNames.contains(proposedName)) { - proposedName = i18n("Video %1", ++i); - } - d->track_name->setText(proposedName); - d->setWindowTitle(i18n("Insert New Track")); - - if (d->exec() == QDialog::Accepted) { - ix = m_timeline->visibleTracksCount() - d->comboTracks->currentIndex(); - if (d->before_select->currentIndex() == 0) { - ix++; - } - TrackInfo info; - info.duration = 0; - info.isMute = false; - info.isLocked = false; - info.effectsList = EffectsList(true); - if (d->video_track->isChecked()) { - info.type = VideoTrack; - info.isBlind = false; - } else { - info.type = AudioTrack; - info.isBlind = true; - } - info.trackName = d->track_name->text(); - auto *addTrack = new AddTrackCommand(this, ix, info, true); - m_commandStack->push(addTrack); - } - delete d; -} - -void CustomTrackView::slotDeleteTrack(int ix) -{ - if (m_timeline->tracksCount() <= 2) { - // TODO: warn user that at least one track is necessary - return; - } - QPointer d = new TrackDialog(m_timeline, parentWidget()); - d->comboTracks->setCurrentIndex(m_timeline->visibleTracksCount() - ix); - d->label->setText(i18n("Delete track")); - d->track_name->setHidden(true); - d->name_label->setHidden(true); - d->before_select->setHidden(true); - d->setWindowTitle(i18n("Delete Track")); - d->video_track->setHidden(true); - d->audio_track->setHidden(true); - if (d->exec() == QDialog::Accepted) { - ix = m_timeline->visibleTracksCount() - d->comboTracks->currentIndex(); - TrackInfo info = m_timeline->getTrackInfo(ix); - deleteTimelineTrack(ix, info); - } - delete d; -} - -void CustomTrackView::slotConfigTracks(int ix) -{ - QPointer d = new TracksConfigDialog(m_timeline, ix, parentWidget()); - if (d->exec() == QDialog::Accepted) { - configTracks(d->tracksList()); - QList toDelete = d->deletedTracks(); - while (!toDelete.isEmpty()) { - int track = toDelete.takeLast(); - TrackInfo info = m_timeline->getTrackInfo(track); - deleteTimelineTrack(track, info); - } - } - delete d; -} - -void CustomTrackView::deleteTimelineTrack(int ix, const TrackInfo &trackinfo) -{ - if (m_timeline->tracksCount() < 2) { - return; - } - // Clear effect stack - clearSelection(); - emit transitionItemSelected(nullptr); - // Make sure the selected track index is not outside range - m_selectedTrack = qBound(1, m_selectedTrack, m_timeline->tracksCount() - 2); - - double startY = getPositionFromTrack(ix) + 1 + m_tracksHeight / 2; - QRectF r(0, startY, sceneRect().width(), m_tracksHeight / 2 - 1); - QList selection = m_scene->items(r); - auto *deleteTrack = new QUndoCommand(); - deleteTrack->setText(QStringLiteral("Delete track")); - - // Remove clips on that track from groups - QList groupsToProceed; - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == GroupWidget) { - if (!groupsToProceed.contains(selection.at(i))) { - groupsToProceed << selection.at(i); - } - } - } - for (int i = 0; i < groupsToProceed.count(); i++) { - AbstractGroupItem *grp = static_cast(groupsToProceed.at(i)); - QList items = grp->childItems(); - QList clipGrpInfos; - QList transitionGrpInfos; - QList newClipGrpInfos; - QList newTransitionGrpInfos; - for (int j = 0; j < items.count(); ++j) { - if (items.at(j)->type() == AVWidget) { - AbstractClipItem *clip = static_cast(items.at(j)); - clipGrpInfos.append(clip->info()); - if (clip->track() != ix) { - newClipGrpInfos.append(clip->info()); - } - } else if (items.at(j)->type() == TransitionWidget) { - AbstractClipItem *clip = static_cast(items.at(j)); - transitionGrpInfos.append(clip->info()); - if (clip->track() != ix) { - newTransitionGrpInfos.append(clip->info()); - } - } - } - if (!clipGrpInfos.isEmpty() || !transitionGrpInfos.isEmpty()) { - // Break group - new GroupClipsCommand(this, clipGrpInfos, transitionGrpInfos, false, deleteTrack != nullptr); - // Rebuild group without clips from track to delete - if (!newClipGrpInfos.isEmpty() || !newTransitionGrpInfos.isEmpty()) { - new GroupClipsCommand(this, newClipGrpInfos, newTransitionGrpInfos, true, true, deleteTrack); - } - } - } - RefreshMonitorCommand *firstRefresh = new RefreshMonitorCommand(this, ItemInfo(), false, true, deleteTrack); - // Delete all clips in selected track - QList ranges; - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == AVWidget) { - ClipItem *item = static_cast(selection.at(i)); - ranges << item->info(); - new AddTimelineClipCommand(this, item->getBinId(), item->info(), item->effectList(), item->clipState(), false, true, false, deleteTrack); - m_scene->removeItem(item); - delete item; - item = nullptr; - } else if (selection.at(i)->type() == TransitionWidget) { - Transition *item = static_cast(selection.at(i)); - ranges << item->info(); - new AddTransitionCommand(this, item->info(), item->transitionEndTrack(), item->toXML(), true, false, deleteTrack); - m_scene->removeItem(item); - delete item; - item = nullptr; - } - } - firstRefresh->updateRange(ranges); - new AddTrackCommand(this, ix, trackinfo, false, deleteTrack); - new RefreshMonitorCommand(this, ranges, true, false, deleteTrack); - m_commandStack->push(deleteTrack); -} - -void CustomTrackView::autoTransition() -{ - QList itemList = scene()->selectedItems(); - if (itemList.count() != 1 || itemList.at(0)->type() != TransitionWidget) { - emit displayMessage(i18n("You must select one transition for this action"), ErrorMessage); - return; - } - Transition *tr = static_cast(itemList.at(0)); - tr->setAutomatic(!tr->isAutomatic()); - QDomElement transition = tr->toXML(); - m_timeline->transitionHandler->updateTransition(transition.attribute(QStringLiteral("tag")), transition.attribute(QStringLiteral("tag")), - transition.attribute(QStringLiteral("transition_btrack")).toInt(), - transition.attribute(QStringLiteral("transition_atrack")).toInt(), tr->startPos(), tr->endPos(), - transition); - setDocumentModified(); -} - -void CustomTrackView::clipNameChanged(const QString &id) -{ - QList list = scene()->items(); - ClipItem *clip = nullptr; - for (int i = 0; i < list.size(); ++i) { - if (list.at(i)->type() == AVWidget) { - clip = static_cast(list.at(i)); - if (clip->getBinId() == id) { - clip->update(); - } - } - } - // viewport()->update(); -} - -void CustomTrackView::getClipAvailableSpace(AbstractClipItem *item, GenTime &minimum, GenTime &maximum) -{ - minimum = GenTime(); - maximum = GenTime(); - QList selection; - selection = m_scene->items(QRectF(0, getPositionFromTrack(item->track()) + m_tracksHeight / 2, sceneRect().width(), 2)); - selection.removeAll(item); - for (int i = 0; i < selection.count(); ++i) { - AbstractClipItem *clip = static_cast(selection.at(i)); - if ((clip != nullptr) && clip->type() == AVWidget) { - if (clip->endPos() <= item->startPos() && clip->endPos() > minimum) { - minimum = clip->endPos(); - } - if (clip->startPos() > item->startPos() && (clip->startPos() < maximum || maximum == GenTime())) { - maximum = clip->startPos(); - } - } - } -} - -void CustomTrackView::getTransitionAvailableSpace(AbstractClipItem *item, GenTime &minimum, GenTime &maximum) -{ - minimum = GenTime(); - maximum = GenTime(); - QList selection; - selection = m_scene->items(QRectF(0, getPositionFromTrack(item->track()) + m_tracksHeight, sceneRect().width(), 2)); - selection.removeAll(item); - for (int i = 0; i < selection.count(); ++i) { - AbstractClipItem *clip = static_cast(selection.at(i)); - if ((clip != nullptr) && clip->type() == TransitionWidget) { - if (clip->endPos() <= item->startPos() && clip->endPos() > minimum) { - minimum = clip->endPos(); - } - if (clip->startPos() > item->startPos() && (clip->startPos() < maximum || maximum == GenTime())) { - maximum = clip->startPos(); - } - } - } -} - -void CustomTrackView::loadGroups(const QDomNodeList &groups) -{ - for (int i = 0; i < groups.count(); ++i) { - QDomNodeList children = groups.at(i).childNodes(); - scene()->clearSelection(); - QList list; - for (int nodeindex = 0; nodeindex < children.count(); ++nodeindex) { - QDomElement elem = children.item(nodeindex).toElement(); - int track = elem.attribute(QStringLiteral("track")).toInt(); - // Ignore items removed after track deletion - if (track == -1) { - continue; - } - int pos = elem.attribute(QStringLiteral("position")).toInt(); - if (elem.tagName() == QLatin1String("clipitem")) { - ClipItem *clip = getClipItemAtStart(GenTime(pos, pCore->getCurrentFps()), track); - if (clip) { - list.append(clip); // clip->setSelected(true); - } - } else { - Transition *clip = getTransitionItemAt(pos, track); - if (clip) { - list.append(clip); // clip->setSelected(true); - } - } - } - groupSelectedItems(list, true); - } -} - -void CustomTrackView::splitAudio(bool warn, const ItemInfo &info, int destTrack, QUndoCommand *masterCommand) -{ - resetSelectionGroup(); - QList selection; - bool hasMasterCommand = masterCommand != nullptr; - if (!hasMasterCommand) { - masterCommand = new QUndoCommand(); - masterCommand->setText(i18n("Split audio")); - } - if (!info.isValid()) { - // Operate on current selection - selection = scene()->selectedItems(); - if (selection.isEmpty()) { - emit displayMessage(i18n("You must select at least one clip for this action"), ErrorMessage); - if (!hasMasterCommand) { - delete masterCommand; - } - return; - } - if (KdenliveSettings::splitaudio()) { - destTrack = m_timeline->audioTarget; - } - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == AVWidget) { - ClipItem *clip = static_cast(selection.at(i)); - if (clip->clipType() == AV || clip->clipType() == Playlist) { - if (clip->parentItem()) { - emit displayMessage(i18n("Cannot split audio of grouped clips"), ErrorMessage); - } else { - new SplitAudioCommand(this, clip->track(), destTrack, clip->startPos(), masterCommand); - } - } - } - } - } else { - new SplitAudioCommand(this, info.track, destTrack, info.startPos, masterCommand); - } - if (masterCommand->childCount() != 0) { - updateTrackDuration(-1, masterCommand); - if (!hasMasterCommand) { - m_commandStack->push(masterCommand); - } - } else { - if (warn) { - emit displayMessage(i18n("No clip to split"), ErrorMessage); - } - if (!hasMasterCommand) { - delete masterCommand; - } - } -} - -void CustomTrackView::setAudioAlignReference() -{ - QList selection = scene()->selectedItems(); - if (selection.isEmpty() || selection.size() > 1) { - emit displayMessage(i18n("You must select exactly one clip for the audio reference."), ErrorMessage); - return; - } - if (m_audioCorrelator != nullptr) { - delete m_audioCorrelator; - m_audioCorrelator = nullptr; - m_audioAlignmentReference = nullptr; - } - if (selection.at(0)->type() == AVWidget) { - ClipItem *clip = static_cast(selection.at(0)); - if (clip->clipType() == AV || clip->clipType() == Audio) { - m_audioAlignmentReference = clip; - Mlt::Producer *prod = m_timeline->track(clip->track())->clipProducer(m_document->renderer()->getBinProducer(clip->getBinId()), clip->clipState()); - if (!prod) { - qCWarning(KDENLIVE_LOG) << "couldn't load producer for clip " << clip->getBinId() << " on track " << clip->track(); - return; - } - AudioEnvelope *envelope = new AudioEnvelope(clip->binClip()->url(), prod); - m_audioCorrelator = new AudioCorrelation(envelope); - connect(m_audioCorrelator, &AudioCorrelation::gotAudioAlignData, this, &CustomTrackView::slotAlignClip); - connect(m_audioCorrelator, &AudioCorrelation::displayMessage, this, &CustomTrackView::displayMessage); - emit displayMessage(i18n("Processing audio, please wait."), ProcessingJobMessage); - } - return; - } - emit displayMessage(i18n("Reference for audio alignment must contain audio data."), ErrorMessage); -} - -void CustomTrackView::alignAudio() -{ - bool referenceOK = true; - if (m_audioCorrelator == nullptr) { - referenceOK = false; - } - if (referenceOK) { - if (!scene()->items().contains(m_audioAlignmentReference)) { - // The reference item has been deleted from the timeline (or so) - referenceOK = false; - } - } - if (!referenceOK) { - emit displayMessage(i18n("Audio alignment reference not yet set."), InformationMessage); - return; - } - - QList selection = scene()->selectedItems(); - for (QGraphicsItem *item : selection) { - if (item->type() == AVWidget) { - - ClipItem *clip = static_cast(item); - if (clip == m_audioAlignmentReference) { - continue; - } - - if (clip->clipType() == AV || clip->clipType() == Audio) { - ItemInfo info = clip->info(); - Mlt::Producer *prod = - m_timeline->track(clip->track())->clipProducer(m_document->renderer()->getBinProducer(clip->getBinId()), clip->clipState()); - if (!prod) { - qCWarning(KDENLIVE_LOG) << "couldn't load producer for clip " << clip->getBinId() << " on track " << clip->track(); - return; - } - AudioEnvelope *envelope = - new AudioEnvelope(clip->binClip()->url(), prod, info.cropStart.frames(pCore->getCurrentFps()), - info.cropDuration.frames(pCore->getCurrentFps()), clip->track(), info.startPos.frames(pCore->getCurrentFps())); - m_audioCorrelator->addChild(envelope); - } - } - } - emit displayMessage(i18n("Processing audio, please wait."), ProcessingJobMessage); -} - -void CustomTrackView::slotAlignClip(int track, int pos, int shift) -{ - auto *moveCommand = new QUndoCommand(); - ClipItem *clip = getClipItemAtStart(GenTime(pos, pCore->getCurrentFps()), track); - if (!clip) { - emit displayMessage(i18n("Cannot find clip to align."), ErrorMessage); - delete moveCommand; - return; - } - GenTime add(shift, pCore->getCurrentFps()); - ItemInfo start = clip->info(); - - ItemInfo end = start; - end.startPos = m_audioAlignmentReference->startPos() + add - m_audioAlignmentReference->cropStart(); - end.endPos = end.startPos + start.cropDuration; - if (end.startPos < GenTime()) { - // Clip would start before 0, so crop it first - GenTime cropBy = -end.startPos; - if (cropBy > start.cropDuration) { - delete moveCommand; - emit displayMessage(i18n("Unable to move clip out of timeline."), ErrorMessage); - return; - } - ItemInfo resized = start; - resized.startPos += cropBy; - - resizeClip(start, resized); - new ResizeClipCommand(this, start, resized, false, false, moveCommand); - - start = clip->info(); - end.startPos += cropBy; - } - - if (itemCollision(clip, end)) { - delete moveCommand; - emit displayMessage(i18n("Unable to move clip due to collision."), ErrorMessage); - return; - } - emit displayMessage(i18n("Clip aligned."), OperationCompletedMessage); - moveCommand->setText(i18n("Auto-align clip")); - new MoveClipCommand(this, start, end, false, true, moveCommand); - updateTrackDuration(clip->track(), moveCommand); - m_commandStack->push(moveCommand); -} - -bool CustomTrackView::doSplitAudio(const GenTime &pos, int track, int destTrack, bool split) -{ - ClipItem *clip = getClipItemAtStart(pos, track); - if (clip == nullptr) { - qCDebug(KDENLIVE_LOG) << "// Cannot find clip to split!!!"; - return false; - } - EffectsList effects; - effects.clone(clip->effectList()); - if (split) { - int start = pos.frames(pCore->getCurrentFps()); - // do not split audio when we are on an audio track - if (m_timeline->getTrackInfo(track).type == AudioTrack) { - return false; - } - if (destTrack == -1) { - destTrack = track - 1; - for (; destTrack > 0; destTrack--) { - TrackInfo info = m_timeline->getTrackInfo(destTrack); - if (info.type == AudioTrack && !info.isLocked) { - if (sceneEditMode() != TimelineMode::NormalEdit) { - break; - } - int blength = m_timeline->getTrackSpaceLength(destTrack, start, false); - if (blength == -1 || blength >= clip->cropDuration().frames(pCore->getCurrentFps())) { - break; - } - } - } - } else { - // Expanding to target track, check it is not locked - TrackInfo info = m_timeline->getTrackInfo(destTrack); - if (info.type != AudioTrack || info.isLocked) { - destTrack = 0; - } else if (sceneEditMode() == TimelineMode::NormalEdit) { - int blength = m_timeline->getTrackSpaceLength(destTrack, start, false); - if (blength >= 0 && blength < clip->cropDuration().frames(pCore->getCurrentFps())) { - destTrack = 0; - } - } - } - if (destTrack == 0) { - emit displayMessage(i18n("No empty space to put clip audio"), ErrorMessage); - return false; - } - ItemInfo info = clip->info(); - info.track = destTrack; - scene()->clearSelection(); - addClip(clip->getBinId(), info, clip->effectList(), PlaylistState::AudioOnly, false); - clip->setSelected(true); - ClipItem *audioClip = getClipItemAtStart(pos, info.track); - if (audioClip) { - if (m_timeline->track(track)->replace(pos.seconds(), m_document->renderer()->getBinVideoProducer(clip->getBinId()))) { - clip->setState(PlaylistState::VideoOnly); - } else { - emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", pos.frames(pCore->getCurrentFps()), destTrack), ErrorMessage); - } - audioClip->setSelected(true); - - // keep video effects, move audio effects to audio clip - int videoIx = 0; - int audioIx = 0; - for (int i = 0; i < effects.count(); ++i) { - if (effects.at(i).attribute(QStringLiteral("type")) == QLatin1String("audio")) { - deleteEffect(track, pos, clip->effect(videoIx)); - audioIx++; - } else { - deleteEffect(destTrack, pos, audioClip->effect(audioIx)); - videoIx++; - } - } - groupSelectedItems(QList() << clip << audioClip, true); - } - - } else { - // unsplit clip: remove audio part and change video part to normal clip - if (clip->parentItem() == nullptr || clip->parentItem()->type() != GroupWidget) { - // qCDebug(KDENLIVE_LOG) << "//CANNOT FIND CLP GRP"; - return false; - } - AbstractGroupItem *grp = static_cast(clip->parentItem()); - QList children = grp->childItems(); - if (children.count() != 2) { - // qCDebug(KDENLIVE_LOG) << "//SOMETHING IS WRONG WITH CLP GRP"; - return false; - } - for (int i = 0; i < children.count(); ++i) { - if (children.at(i) != clip) { - ClipItem *clp = static_cast(children.at(i)); - ItemInfo info = clip->info(); - deleteClip(clp->info()); - if (!m_timeline->track(info.track)->replace(info.startPos.seconds(), m_document->renderer()->getBinProducer(clip->getBinId()))) { - emit displayMessage(i18n("Cannot update clip (time: %1, track: %2)", info.startPos.frames(pCore->getCurrentFps()), info.track), - ErrorMessage); - return false; - } - clip->setState(PlaylistState::Original); - - // re-add audio effects - for (int j = 0; j < effects.count(); ++j) { - if (effects.at(j).attribute(QStringLiteral("type")) == QLatin1String("audio")) { - addEffect(track, pos, effects.at(j)); - } - } - - break; - } - } - clip->setFlag(QGraphicsItem::ItemIsMovable, true); - m_document->clipManager()->removeGroup(grp); - if (grp == m_selectionGroup) { - m_selectionGroup = nullptr; - } - scene()->destroyItemGroup(grp); - } - return true; -} - -void CustomTrackView::setClipType(PlaylistState::ClipState state) -{ - QString text = i18n("Audio and Video"); - if (state == PlaylistState::VideoOnly) { - text = i18n("Video only"); - } else if (state == PlaylistState::AudioOnly) { - text = i18n("Audio only"); - } else if (state == PlaylistState::Disabled) { - text = i18n("Disabled"); - } - - resetSelectionGroup(); - QList selection = scene()->selectedItems(); - if (selection.isEmpty()) { - emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage); - return; - } - auto *videoCommand = new QUndoCommand(); - videoCommand->setText(text); - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == AVWidget) { - ClipItem *clip = static_cast(selection.at(i)); - if (clip->clipType() == AV || clip->clipType() == Playlist || clip->clipType() == Audio) { - if (clip->parentItem()) { - emit displayMessage(i18n("Cannot change grouped clips"), ErrorMessage); - } else { - new ChangeClipTypeCommand(this, clip->info(), state, clip->clipState(), videoCommand); - } - } - } - } - m_commandStack->push(videoCommand); -} - -void CustomTrackView::disableClip() -{ - resetSelectionGroup(); - QList selection = scene()->selectedItems(); - if (selection.isEmpty()) { - emit displayMessage(i18n("You must select one clip for this action"), ErrorMessage); - return; - } - auto *videoCommand = new QUndoCommand(); - videoCommand->setText(i18n("Disable clip")); - QList range; - // Expand groups - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == GroupWidget) { - QList children = selection.at(i)->childItems(); - for (QGraphicsItem *item : children) { - if (!selection.contains(item)) { - selection << item; - } - } - } else if ((selection.at(i)->parentItem() != nullptr) && !selection.contains(selection.at(i)->parentItem())) { - QList children = selection.at(i)->parentItem()->childItems(); - for (QGraphicsItem *item : children) { - if (!selection.contains(item)) { - selection << item; - } - } - } - } - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == AVWidget) { - ClipItem *clip = static_cast(selection.at(i)); - ClipType cType = clip->clipType(); - if (cType == AV || cType == Playlist || cType == Audio) { - PlaylistState::ClipState currentStatus = clip->clipState(); - PlaylistState::ClipState newStatus; - if (currentStatus == PlaylistState::Disabled) { - newStatus = clip->originalState(); - } else { - newStatus = PlaylistState::Disabled; - } - new ChangeClipTypeCommand(this, clip->info(), newStatus, currentStatus, videoCommand); - if (newStatus != PlaylistState::AudioOnly && currentStatus != PlaylistState::AudioOnly && cType != Audio) { - range << clip->info(); - } - } - } - } - m_commandStack->push(videoCommand); - monitorRefresh(range, true); -} - -void CustomTrackView::monitorRefresh(const QList &range, bool invalidateRange) -{ - bool refreshMonitor = false; - for (int i = 0; i < range.count(); i++) { - if (range.at(i).contains(GenTime(m_cursorPos, pCore->getCurrentFps()))) { - refreshMonitor = true; - } - if (invalidateRange) { - m_timeline->invalidateRange(range.at(i)); - } - } - if (refreshMonitor) { - m_document->renderer()->doRefresh(); - } -} - -void CustomTrackView::monitorRefresh(const ItemInfo &range, bool invalidateRange) -{ - if (range.contains(GenTime(m_cursorPos, pCore->getCurrentFps()))) { - m_document->renderer()->doRefresh(); - } - if (invalidateRange) { - m_timeline->invalidateRange(range); - } -} - -void CustomTrackView::monitorRefresh(bool invalidateRange) -{ - m_document->renderer()->doRefresh(); - if (invalidateRange) { - m_timeline->invalidateRange(); - } -} - -void CustomTrackView::doChangeClipType(const ItemInfo &info, PlaylistState::ClipState state) -{ - ClipItem *clip = getClipItemAtStart(info.startPos, info.track); - if (clip == nullptr) { - emit displayMessage(i18n("Cannot find clip to edit (time: %1, track: %2)", info.startPos.frames(pCore->getCurrentFps()), - m_timeline->getTrackInfo(info.track).trackName), - ErrorMessage); - return; - } - Mlt::Producer *prod; - double speed = clip->speed(); - PlaylistState::ClipState previousState = clip->clipState(); - if (state == PlaylistState::VideoOnly) { - prod = m_document->renderer()->getBinVideoProducer(clip->getBinId()); - } else { - prod = m_document->renderer()->getBinProducer(clip->getBinId()); - } - if (speed != 1) { - QLocale locale; - QString url = prod->get("resource"); - Track::SlowmoInfo slowmoInfo; - slowmoInfo.speed = speed; - slowmoInfo.strobe = 1; - slowmoInfo.state = state; - Mlt::Producer *copy = m_document->renderer()->getSlowmotionProducer(slowmoInfo.toString(locale) + url); - if (copy == nullptr) { - // create mute slowmo producer - url.prepend(locale.toString(speed) + QLatin1Char(':')); - Mlt::Properties passProperties; - Mlt::Properties original(prod->get_properties()); - passProperties.pass_list(original, ClipController::getPassPropertiesList(false)); - copy = m_timeline->track(info.track)->buildSlowMoProducer(passProperties, url, clip->getBinId(), slowmoInfo); - } - if (copy == nullptr) { - // Failed to get slowmo producer, error - qCDebug(KDENLIVE_LOG) << "Failed to get slowmo producer, error"; - return; - } - prod = copy; - } - if ((prod != nullptr) && prod->is_valid() && m_timeline->track(info.track)->replace(info.startPos.seconds(), prod, state, previousState)) { - clip->setState(state); - clip->update(); - if (clip->clipType() != Audio && state != PlaylistState::Disabled && previousState != PlaylistState::Disabled && - (previousState == PlaylistState::AudioOnly || state == PlaylistState::AudioOnly)) { - // Disabled state is handled upstream, so check if we switch to / from an audio state - monitorRefresh(info, true); - } - } else { - // Changing clip type failed - emit displayMessage( - i18n("Cannot update clip (time: %1, track: %2)", info.startPos.frames(pCore->getCurrentFps()), m_timeline->getTrackInfo(info.track).trackName), - ErrorMessage); - return; - } -} - -void CustomTrackView::updateClipTypeActions(ClipItem *clip) -{ - bool hasAudio; - bool hasAV; - if (clip == nullptr) { - m_clipTypeGroup->setEnabled(false); - hasAudio = false; - hasAV = false; - } else { - switch (clip->clipType()) { - case AV: - case Playlist: - hasAudio = true; - hasAV = true; - m_clipTypeGroup->setEnabled(true); - break; - case Audio: - hasAudio = true; - hasAV = false; - m_clipTypeGroup->setEnabled(true); - break; - default: - hasAudio = false; - hasAV = false; - m_clipTypeGroup->setEnabled(false); - } - QList actions = m_clipTypeGroup->actions(); - for (int i = 0; i < actions.count(); ++i) { - if (actions.at(i)->data().toInt() == clip->clipState()) { - actions.at(i)->setChecked(true); - break; - } - } - } - for (int i = 0; i < m_audioActions.count(); ++i) { - m_audioActions.at(i)->setEnabled(hasAudio); - } - for (int i = 0; i < m_avActions.count(); ++i) { - m_avActions.at(i)->setEnabled(hasAV); - } -} - -void CustomTrackView::slotGoToMarker(QAction *action) -{ - int pos = action->data().toInt(); - seekCursorPos(pos); -} - -void CustomTrackView::reloadTransitionLumas() -{ - QString lumaNames; - QString lumaFiles; - QDomElement lumaTransition = MainWindow::transitions.getEffectByTag(QStringLiteral("luma"), QStringLiteral("luma")); - QDomNodeList params_list = lumaTransition.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < params_list.count(); ++i) { - QDomElement e = params_list.item(i).toElement(); - if (e.attribute(QStringLiteral("tag")) == QLatin1String("resource")) { - lumaNames = e.attribute(QStringLiteral("paramlistdisplay")); - lumaFiles = e.attribute(QStringLiteral("paramlist")); - break; - } - } - - QList itemList = items(); - Transition *transitionitem; - QDomElement transitionXml; - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == TransitionWidget) { - transitionitem = static_cast(itemList.at(i)); - transitionXml = transitionitem->toXML(); - if (transitionXml.attribute(QStringLiteral("id")) == QLatin1String("luma") && - transitionXml.attribute(QStringLiteral("tag")) == QLatin1String("luma")) { - QDomNodeList params = transitionXml.elementsByTagName(QStringLiteral("parameter")); - for (int j = 0; j < params.count(); ++j) { - QDomElement e = params.item(j).toElement(); - if (e.attribute(QStringLiteral("tag")) == QLatin1String("resource")) { - e.setAttribute(QStringLiteral("paramlistdisplay"), lumaNames); - e.setAttribute(QStringLiteral("paramlist"), lumaFiles); - break; - } - } - } - if (transitionXml.attribute(QStringLiteral("id")) == QLatin1String("composite") && - transitionXml.attribute(QStringLiteral("tag")) == QLatin1String("composite")) { - QDomNodeList params = transitionXml.elementsByTagName(QStringLiteral("parameter")); - for (int j = 0; j < params.count(); ++j) { - QDomElement e = params.item(j).toElement(); - if (e.attribute(QStringLiteral("tag")) == QLatin1String("luma")) { - e.setAttribute(QStringLiteral("paramlistdisplay"), lumaNames); - e.setAttribute(QStringLiteral("paramlist"), lumaFiles); - break; - } - } - } - } - } - emit transitionItemSelected(nullptr); -} - -double CustomTrackView::fps() const -{ - return pCore->getCurrentFps(); -} - -void CustomTrackView::updateProjectFps() -{ - // update all clips to the new fps - resetSelectionGroup(); - scene()->clearSelection(); - if (m_dragItem) { - m_dragItem->setMainSelectedClip(false); - } - m_dragItem = nullptr; - QList itemList = items(); - for (int i = 0; i < itemList.count(); ++i) { - // remove all items and re-add them one by one - if (itemList.at(i) != m_cursorLine && itemList.at(i)->parentItem() == nullptr) { - m_scene->removeItem(itemList.at(i)); - } - } - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->parentItem() == nullptr && (itemList.at(i)->type() == AVWidget || itemList.at(i)->type() == TransitionWidget)) { - AbstractClipItem *clip = static_cast(itemList.at(i)); - clip->updateFps(pCore->getCurrentFps()); - m_scene->addItem(clip); - } else if (itemList.at(i)->type() == GroupWidget) { - AbstractGroupItem *grp = static_cast(itemList.at(i)); - QList children = grp->childItems(); - for (int j = 0; j < children.count(); ++j) { - if (children.at(j)->type() == AVWidget || children.at(j)->type() == TransitionWidget) { - AbstractClipItem *clip = static_cast(children.at(j)); - clip->setFlag(QGraphicsItem::ItemIsMovable, true); - clip->updateFps(pCore->getCurrentFps()); - } - } - m_document->clipManager()->removeGroup(grp); - m_scene->addItem(grp); - if (grp == m_selectionGroup) { - m_selectionGroup = nullptr; - } - scene()->destroyItemGroup(grp); - scene()->clearSelection(); - /*for (int j = 0; j < children.count(); ++j) { - if (children.at(j)->type() == AVWidget || children.at(j)->type() == TRANSITIONWIDGET) { - //children.at(j)->setParentItem(0); - children.at(j)->setSelected(true); - } - }*/ - groupSelectedItems(children, true); - } else if (itemList.at(i)->type() == GUIDEITEM) { - Guide *g = static_cast(itemList.at(i)); - g->updatePos(); - m_scene->addItem(g); - } - } - viewport()->update(); -} - -void CustomTrackView::slotTrackDown() -{ - int ix; - if (m_selectedTrack > 1) { - ix = m_selectedTrack - 1; - } else { - ix = m_timeline->tracksCount() - 1; - } - slotSelectTrack(ix); -} - -void CustomTrackView::slotTrackUp() -{ - int ix; - if (m_selectedTrack < m_timeline->tracksCount() - 1) { - ix = m_selectedTrack + 1; - } else { - ix = 1; - } - slotSelectTrack(ix); -} - -int CustomTrackView::selectedTrack() const -{ - return m_selectedTrack; -} - -QStringList CustomTrackView::selectedClips() const -{ - QStringList clipIds; - QList selection = m_scene->selectedItems(); - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == AVWidget) { - ClipItem *item = static_cast(selection.at(i)); - clipIds << item->getBinId(); - } - } - return clipIds; -} - -void CustomTrackView::slotSelectTrack(int ix, bool switchTarget) -{ - m_selectedTrack = qBound(1, ix, m_timeline->tracksCount() - 1); - emit updateTrackHeaders(); - m_timeline->slotShowTrackEffects(ix); - QRectF rect(mapToScene(QPoint(10, 0)).x(), getPositionFromTrack(ix), 10, m_tracksHeight); - ensureVisible(rect, 0, 0); - viewport()->update(); - if (switchTarget) { - m_timeline->switchTrackTarget(); - } -} - -void CustomTrackView::slotSelectClipsInTrack() -{ - QRectF rect(0, getPositionFromTrack(m_selectedTrack) + m_tracksHeight / 2, sceneRect().width(), m_tracksHeight / 2 - 1); - resetSelectionGroup(); - QList selection = m_scene->items(rect); - m_scene->clearSelection(); - QList list; - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == AVWidget || selection.at(i)->type() == TransitionWidget || selection.at(i)->type() == GroupWidget) { - list.append(selection.at(i)); - } - } - groupSelectedItems(list, false, true); -} - -void CustomTrackView::slotSelectAllClips() -{ - m_scene->clearSelection(); - resetSelectionGroup(); - QList selection = m_scene->items(); - QList list; - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->parentItem() == nullptr && (selection.at(i)->type() == AVWidget || selection.at(i)->type() == TransitionWidget)) { - AbstractClipItem *item = static_cast(selection.at(i)); - if (!item->isItemLocked()) { - list << item; - } - } else if (selection.at(i)->type() == GroupWidget) { - AbstractGroupItem *item = static_cast(selection.at(i)); - if (!item->isItemLocked()) { - list << item; - } - } - } - groupSelectedItems(list, false, true); -} - -void CustomTrackView::selectClip(bool add, bool group, int track, int pos) -{ - QRectF rect; - if (track != -1 && pos != -1) { - rect = QRectF(pos, getPositionFromTrack(track) + m_tracksHeight / 2, 1, 1); - } else { - rect = QRectF(m_cursorPos, getPositionFromTrack(m_selectedTrack) + m_tracksHeight / 2, 1, 1); - } - QList selection = m_scene->items(rect); - resetSelectionGroup(group); - if (!group) { - m_scene->clearSelection(); - } - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == AVWidget) { - selection.at(i)->setSelected(add); - break; - } - } - if (group) { - groupSelectedItems(); - } -} - -void CustomTrackView::selectTransition(bool add, bool group) -{ - QRectF rect(m_cursorPos, getPositionFromTrack(m_selectedTrack) + m_tracksHeight, 1, 1); - QList selection = m_scene->items(rect); - resetSelectionGroup(group); - if (!group) { - m_scene->clearSelection(); - } - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == TransitionWidget) { - selection.at(i)->setSelected(add); - break; - } - } - if (group) { - groupSelectedItems(); - } -} - -QStringList CustomTrackView::extractTransitionsLumas() -{ - QStringList urls; - QList itemList = items(); - Transition *transitionitem; - QDomElement transitionXml; - for (int i = 0; i < itemList.count(); ++i) { - if (itemList.at(i)->type() == TransitionWidget) { - transitionitem = static_cast(itemList.at(i)); - transitionXml = transitionitem->toXML(); - // luma files in transitions are in "resource" property - QString luma = EffectsList::parameter(transitionXml, QStringLiteral("resource")); - if (!luma.isEmpty()) { - urls << QUrl::fromLocalFile(luma).toLocalFile(); - } - } - } - urls.removeDuplicates(); - return urls; -} - -void CustomTrackView::setEditMode(TimelineMode::EditMode mode) -{ - m_scene->setEditMode(mode); -} - -void CustomTrackView::checkTrackSequence(int track) -{ - QList times = m_document->renderer()->checkTrackSequence(track); - QRectF rect(0, getPositionFromTrack(track) + m_tracksHeight / 2, sceneRect().width(), 2); - QList selection = m_scene->items(rect); - QList timelineList; - timelineList.append(0); - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == AVWidget) { - ClipItem *clip = static_cast(selection.at(i)); - int start = clip->startPos().frames(pCore->getCurrentFps()); - int end = clip->endPos().frames(pCore->getCurrentFps()); - if (!timelineList.contains(start)) { - timelineList.append(start); - } - if (!timelineList.contains(end)) { - timelineList.append(end); - } - } - } - qSort(timelineList); - // qCDebug(KDENLIVE_LOG) << "// COMPARE:\n" << times << '\n' << timelineList << "\n-------------------"; - if (times != timelineList) { - KMessageBox::sorry(this, i18n("error"), i18n("TRACTOR")); - } -} - -int CustomTrackView::insertZone(TimelineMode::EditMode sceneMode, const QString &clipId, QPoint binZone) -{ - /* - bool extractAudio = true; - bool extractVideo = true; - ProjectClip *clp = m_document->getBinClip(clipId); - if (!clp) { - emit displayMessage(i18n("Select a Bin Clip to perform operation"), ErrorMessage); - return -1; - } - ClipType cType = clp->clipType(); - if (KdenliveSettings::splitaudio()) { - if (m_timeline->audioTarget == -1 || m_timeline->getTrackInfo(m_timeline->audioTarget).isLocked) { - extractAudio = false; - } - if (cType == Audio || m_timeline->videoTarget == -1 || m_timeline->getTrackInfo(m_timeline->videoTarget).isLocked) { - extractVideo = false; - } - } else if (m_timeline->getTrackInfo(m_selectedTrack).isLocked) { - // Cannot perform an Extract operation on a locked track - emit displayMessage(i18n("Cannot perform operation on a locked track"), ErrorMessage); - return -1; - } - if (binZone.isNull()) { - return -1; - } - QPoint timelineZone; - if (KdenliveSettings::useTimelineZoneToEdit()) { - timelineZone = m_document->zone(); - timelineZone.setY(timelineZone.y() + 1); - } else { - timelineZone.setX(seekPosition()); - timelineZone.setY(-1); - } - ItemInfo info; - int binLength = binZone.y() - binZone.x() + 1; - int timelineLength = timelineZone.y() - timelineZone.x(); - if (KdenliveSettings::useTimelineZoneToEdit()) { - if (clp->hasLimitedDuration()) { - // Make sure insert duration is not longer than clip length - timelineLength = qMin(timelineLength, (int)clp->duration().frames(pCore->getCurrentFps()) - binZone.x()); - } else if (timelineLength > clp->duration().frames(pCore->getCurrentFps())) { - // Update source clip max length - clp->setProducerProperty(QStringLiteral("length"), timelineLength + 1); - } - } - info.startPos = GenTime(timelineZone.x(), pCore->getCurrentFps()); - info.cropStart = GenTime(binZone.x(), pCore->getCurrentFps()); - info.endPos = info.startPos + GenTime(KdenliveSettings::useTimelineZoneToEdit() ? timelineLength : binLength, pCore->getCurrentFps()); - info.cropDuration = info.endPos - info.startPos; - info.track = m_selectedTrack; - auto *addCommand = new QUndoCommand(); - addCommand->setText(i18n("Insert clip")); - if (sceneMode == TimelineMode::OverwriteEdit) { - // We clear the selected zone in all non locked tracks - extractZone(QPoint(timelineZone.x(), info.endPos.frames(pCore->getCurrentFps())), false, QList(), addCommand); - } else { - // Cut and move clips forward - cutTimeline(timelineZone.x(), QList(), QList(), addCommand); - new AddSpaceCommand(this, info, QList(), true, addCommand); - } - if (KdenliveSettings::splitaudio()) { - if (extractVideo) { - info.track = m_timeline->videoTarget; - if (extractAudio) { - new AddTimelineClipCommand(this, clipId, info, EffectsList(), PlaylistState::Original, true, false, true, addCommand); - } else { - new AddTimelineClipCommand(this, clipId, info, EffectsList(), PlaylistState::VideoOnly, true, false, true, addCommand); - } - } else if (extractAudio) { - // Extract audio only - info.track = m_timeline->audioTarget; - new AddTimelineClipCommand(this, clipId, info, EffectsList(), cType == Audio ? PlaylistState::Original : PlaylistState::AudioOnly, true, false, - false, addCommand); - } else { - emit displayMessage(i18n("No target track(s) selected"), InformationMessage); - } - } else { - new AddTimelineClipCommand(this, clipId, info, EffectsList(), PlaylistState::Original, true, false, true, addCommand); - } - // Automatic audio split - if (KdenliveSettings::splitaudio() && extractVideo && extractAudio) { - if (!m_timeline->getTrackInfo(m_timeline->audioTarget).isLocked && clp->isSplittable()) { - splitAudio(false, info, m_timeline->audioTarget, addCommand); - } - } - updateTrackDuration(info.track, addCommand); - m_commandStack->push(addCommand); - selectClip(true, false, m_selectedTrack, timelineZone.x()); - return info.endPos.frames(pCore->getCurrentFps()); - */ - return 0; -} - -void CustomTrackView::clearSelection(bool emitInfo) -{ - if (m_dragItem) { - m_dragItem->setSelected(false); - } - resetSelectionGroup(); - scene()->clearSelection(); - if (m_dragItem) { - m_dragItem->setMainSelectedClip(false); - } - m_dragItem = nullptr; - if (emitInfo) { - emit clipItemSelected(nullptr); - emit transitionItemSelected(nullptr); - } -} - -void CustomTrackView::updatePalette() -{ - if (m_cursorLine) { - QPen pen1 = m_cursorLine->pen(); - QColor line(palette().text().color()); - line.setAlpha(pen1.color().alpha()); - pen1.setColor(line); - m_cursorLine->setPen(pen1); - } - QIcon razorIcon = KoIconUtils::themedIcon(QStringLiteral("edit-cut")); - m_razorCursor = QCursor(razorIcon.pixmap(32, 32)); - KColorScheme scheme(palette().currentColorGroup(), KColorScheme::Window, KSharedConfig::openConfig(KdenliveSettings::colortheme())); - m_selectedTrackColor = scheme.background(KColorScheme::ActiveBackground).color(); - m_selectedTrackColor.setAlpha(150); - m_lockedTrackColor = scheme.background(KColorScheme::NegativeBackground).color(); - m_lockedTrackColor.setAlpha(150); -} - -void CustomTrackView::removeTipAnimation() -{ - if (m_visualTip) { - scene()->removeItem(m_visualTip); - m_keyPropertiesTimer->stop(); - delete m_keyProperties; - m_keyProperties = nullptr; - delete m_visualTip; - m_visualTip = nullptr; - } -} - -bool CustomTrackView::hasAudio(int track) const -{ - QRectF rect(0, (double)(getPositionFromTrack(track) + 1), (double)sceneRect().width(), (double)(m_tracksHeight - 1)); - QList collisions = scene()->items(rect, Qt::IntersectsItemBoundingRect); - for (int i = 0; i < collisions.count(); ++i) { - QGraphicsItem *item = collisions.at(i); - if (!item->isEnabled()) { - continue; - } - if (item->type() == AVWidget) { - ClipItem *clip = static_cast(item); - if (clip->clipState() != PlaylistState::VideoOnly && (clip->clipType() == Audio || clip->clipType() == AV || clip->clipType() == Playlist)) { - return true; - } - } - } - return false; -} - -void CustomTrackView::slotAddTrackEffect(const QDomElement &effect, int ix) -{ - EffectsController::initTrackEffect(effect); - auto *effectCommand = new QUndoCommand(); - QString effectName; - if (effect.tagName() == QLatin1String("effectgroup")) { - effectName = effect.attribute(QStringLiteral("name")); - } else { - QDomElement namenode = effect.firstChildElement(QStringLiteral("name")); - if (!namenode.isNull()) { - effectName = i18n(namenode.text().toUtf8().data()); - } else { - effectName = i18n("effect"); - } - } - effectCommand->setText(i18n("Add %1", effectName)); - if (effect.tagName() == QLatin1String("effectgroup")) { - QDomNodeList effectlist = effect.elementsByTagName(QStringLiteral("effect")); - for (int j = 0; j < effectlist.count(); ++j) { - QDomElement trackeffect = effectlist.at(j).toElement(); - if (trackeffect.attribute(QStringLiteral("unique"), QStringLiteral("0")) != QLatin1String("0") && - m_timeline->hasTrackEffect(ix, trackeffect.attribute(QStringLiteral("tag")), trackeffect.attribute(QStringLiteral("id"))) != -1) { - emit displayMessage(i18n("Effect already present in track"), ErrorMessage); - continue; - } - new AddEffectCommand(this, ix, GenTime(-1), trackeffect, true, effectCommand); - } - } else { - if (effect.attribute(QStringLiteral("unique"), QStringLiteral("0")) != QLatin1String("0") && - m_timeline->hasTrackEffect(ix, effect.attribute(QStringLiteral("tag")), effect.attribute(QStringLiteral("id"))) != -1) { - emit displayMessage(i18n("Effect already present in track"), ErrorMessage); - delete effectCommand; - return; - } - new AddEffectCommand(this, ix, GenTime(-1), effect, true, effectCommand); - } - - if (effectCommand->childCount() > 0) { - m_commandStack->push(effectCommand); - } else { - delete effectCommand; - } -} - -void CustomTrackView::updateTrackDuration(int track, QUndoCommand *command) -{ - Q_UNUSED(command) - - QList tracks; - if (track >= 0) { - tracks << track; - } else { - // negative track number -> update all tracks - for (int i = 1; i < m_timeline->tracksCount(); ++i) { - tracks << i; - } - } - /*for (int i = 0; i < tracks.count(); ++i) { - int t = tracks.at(i); - // t + 1 because of black background track - int duration = m_document->renderer()->mltTrackDuration(t + 1); - if (duration != m_document->trackDuration(t)) { - m_document->setTrackDuration(t, duration); - - // update effects - EffectsList effects = m_document->getTrackEffects(t); - for (int j = 0; j < effects.count(); ++j) { - // TODO - // - lookout for keyframable parameters and update them so all keyframes are in the new range (0 - duration) - // - update the effectstack if necessary - // - } - } - }*/ -} - -void CustomTrackView::adjustEffects(ClipItem *item, const ItemInfo &oldInfo, QUndoCommand *command) -{ - QMap effects = item->adjustEffectsToDuration(oldInfo); - if (!effects.isEmpty()) { - QMap::const_iterator i = effects.constBegin(); - while (i != effects.constEnd()) { - new EditEffectCommand(this, item->track(), item->startPos(), i.value(), item->effect(i.key()), - i.value().attribute(QStringLiteral("kdenlive_ix")).toInt(), true, true, false, command); - ++i; - } - } -} - -void CustomTrackView::slotGotFilterJobResults(const QString & /*id*/, int startPos, int track, const stringMap &filterParams, const stringMap &extra) -{ - ClipItem *clip = getClipItemAtStart(GenTime(startPos, pCore->getCurrentFps()), track); - if (clip == nullptr) { - emit displayMessage(i18n("Cannot find clip for effect update %1.", extra.value("finalfilter")), ErrorMessage); - return; - } - QDomElement newEffect; - QDomElement effect = clip->effectAtIndex(clip->selectedEffectIndex()); - if (effect.attribute(QStringLiteral("id")) == extra.value(QStringLiteral("finalfilter"))) { - newEffect = effect.cloneNode().toElement(); - QMap::const_iterator i = filterParams.constBegin(); - while (i != filterParams.constEnd()) { - EffectsList::setParameter(newEffect, i.key(), i.value()); - ++i; - } - EditEffectCommand *command = - new EditEffectCommand(this, clip->track(), clip->startPos(), effect, newEffect, clip->selectedEffectIndex(), true, true, true); - m_commandStack->push(command); - emit clipItemSelected(clip); - } else { - emit displayMessage(i18n("Cannot find effect to update %1.", extra.value("finalfilter")), ErrorMessage); - } -} - -void CustomTrackView::slotImportClipKeyframes(GraphicsRectItem type, const ItemInfo &info, const QDomElement &xml, QMap keyframes) -{ - ClipItem *item = nullptr; - ItemInfo srcInfo; - if (keyframes.isEmpty()) { - if (type == TransitionWidget) { - // We want to import keyframes to a transition - if (!m_selectionGroup) { - emit displayMessage(i18n("You need to select one clip and one transition"), ErrorMessage); - return; - } - // Make sure there is no collision - QList children = m_selectionGroup->childItems(); - for (int i = 0; i < children.count(); ++i) { - if (children.at(i)->type() == AVWidget) { - item = static_cast(children.at(i)); - srcInfo = item->info(); - break; - } - } - } else { - // Import keyframes from current clip to its effect - if ((m_dragItem != nullptr) && m_dragItem->type() == AVWidget) { - item = static_cast(m_dragItem); - } - } - if (!item) { - emit displayMessage(i18n("No clip found"), ErrorMessage); - return; - } - keyframes = item->binClip()->analysisData(); - } - if (keyframes.isEmpty()) { - emit displayMessage(i18n("No keyframe data found in clip"), ErrorMessage); - return; - } - /*QPointer import = new KeyframeImport(srcInfo, info, keyframes, m_document->timecode(), xml, this); - if (import->exec() != QDialog::Accepted) { - delete import; - return; - } - QString keyframeData = import->selectedData(); - QString tag = import->selectedTarget(); - emit importKeyframes(type, tag, keyframeData); - delete import; - */ -} - -void CustomTrackView::slotReplaceTimelineProducer(const QString &id) -{ - Mlt::Producer *prod = m_document->renderer()->getBinProducer(id); - if (!prod) { - qDebug()<<"* ** ERROR, CANNOT FIND BIN CLIP : "<renderer()->getBinVideoProducer(id); - QList allSlows; - for (int i = 1; i < m_timeline->tracksCount(); i++) { - allSlows << m_timeline->track(i)->getSlowmotionInfos(id); - } - QLocale locale; - QString url = prod->get("resource"); - // generate all required slowmo producers - QStringList processedUrls; - QMap newSlowMos; - for (int i = 0; i < allSlows.count(); i++) { - // find out speed and strobe values - Track::SlowmoInfo info = allSlows.at(i); - QString wrapUrl = QStringLiteral("timewarp:") + locale.toString(info.speed) + QLatin1Char(':') + url; - // build slowmo producer - if (processedUrls.contains(wrapUrl)) { - continue; - } - processedUrls << wrapUrl; - Mlt::Producer *slowProd = new Mlt::Producer(*prod->profile(), nullptr, wrapUrl.toUtf8().constData()); - if (!slowProd->is_valid()) { - qCDebug(KDENLIVE_LOG) << "++++ FAILED TO CREATE SLOWMO PROD"; - continue; - } - // if (strobe > 1) slowProd->set("strobe", strobe); - QString producerid = QStringLiteral("slowmotion:") + id + QLatin1Char(':') + info.toString(locale); - slowProd->set("id", producerid.toUtf8().constData()); - newSlowMos.insert(info.toString(locale), slowProd); - } - QList toUpdate; - for (int i = 1; i < m_timeline->tracksCount(); i++) { - toUpdate << m_timeline->track(i)->replaceAll(id, prod, videoProd, newSlowMos); - } - - // update slowmotion storage - QMapIterator i(newSlowMos); - while (i.hasNext()) { - i.next(); - Mlt::Producer *sprod = i.value(); - m_document->renderer()->storeSlowmotionProducer(i.key() + url, sprod, true); - } - if (!toUpdate.isEmpty()) { - QMetaObject::invokeMethod(this, "monitorRefresh", Qt::QueuedConnection, Q_ARG(QList, toUpdate), Q_ARG(bool, true)); - } - m_timeline->refreshTractor(); -} - -void CustomTrackView::slotPrepareTimelineReplacement(const QString &id) -{ - for (int i = 1; i < m_timeline->tracksCount(); i++) { - m_timeline->track(i)->replaceId(id); - } -} - -void CustomTrackView::slotUpdateTimelineProducer(const QString &id) -{ - Mlt::Producer *prod = m_document->renderer()->getBinProducer(id); - for (int i = 1; i < m_timeline->tracksCount(); i++) { - m_timeline->track(i)->updateEffects(id, prod); - } -} - -bool CustomTrackView::hasSelection() const -{ - return ((m_selectionGroup != nullptr) || (m_dragItem != nullptr)); -} - -void CustomTrackView::exportTimelineSelection(QString path) -{ - if ((m_selectionGroup == nullptr) && (m_dragItem == nullptr)) { - qCDebug(KDENLIVE_LOG) << "/// ARGH, NO SELECTION GRP"; - emit displayMessage(i18n("No clips and transitions selected in timeline for exporting."), ErrorMessage); - return; - } - if (path.isEmpty()) { - QString clipFolder = KRecentDirs::dir(QStringLiteral(":KdenliveClipFolder")); - if (clipFolder.isEmpty()) { - clipFolder = QDir::homePath(); - } - path = QFileDialog::getSaveFileName(this, i18n("Save Timeline Selection"), clipFolder, i18n("MLT playlist (*.mlt)")); - if (path.isEmpty()) { - return; - } - } - QList children; - QRectF bounding; - if (m_selectionGroup) { - children = m_selectionGroup->childItems(); - bounding = m_selectionGroup->sceneBoundingRect(); - } else { - // only one clip selected - children << m_dragItem; - bounding = m_dragItem->sceneBoundingRect(); - } - int firstTrack = getTrackFromPos(bounding.bottom()); - int lastTrack = getTrackFromPos(bounding.top()); - // Build export playlist - auto *newTractor = new Mlt::Tractor(*(m_document->renderer()->getProducer()->profile())); - Mlt::Field *field = newTractor->field(); - for (int i = firstTrack; i <= lastTrack; i++) { - QScopedPointer newTrackPlaylist(new Mlt::Playlist(*newTractor->profile())); - newTractor->set_track(*newTrackPlaylist, i - firstTrack); - } - int startOffest = m_projectDuration; - // Find first frame of selection - for (int i = 0; i < children.count(); ++i) { - QGraphicsItem *item = children.at(i); - if (item->type() != TransitionWidget && item->type() != AVWidget) { - continue; - } - AbstractClipItem *it = static_cast(item); - if (!it) { - continue; - } - int pos = it->startPos().frames(pCore->getCurrentFps()); - if (pos < startOffest) { - startOffest = pos; - } - } - for (int i = 0; i < children.count(); ++i) { - QGraphicsItem *item = children.at(i); - if (item->type() == AVWidget) { - ClipItem *clip = static_cast(item); - int track = clip->track() - firstTrack; - m_timeline->duplicateClipOnPlaylist(clip->track(), clip->startPos().seconds(), startOffest, newTractor->track(track)); - } else if (item->type() == TransitionWidget) { - Transition *tr = static_cast(item); - int a_track = qBound(0, tr->transitionEndTrack() - firstTrack, lastTrack - firstTrack + 1); - int b_track = qBound(0, tr->track() - firstTrack, lastTrack - firstTrack + 1); - m_timeline->transitionHandler->duplicateTransitionOnPlaylist(tr->startPos().frames(pCore->getCurrentFps()) - startOffest, - tr->endPos().frames(pCore->getCurrentFps()) - startOffest, tr->transitionTag(), - tr->toXML(), a_track, b_track, field); - } - } - Mlt::Consumer xmlConsumer(*newTractor->profile(), ("xml:" + path).toUtf8().constData()); - xmlConsumer.set("terminate_on_pause", 1); - xmlConsumer.connect(*newTractor); - xmlConsumer.run(); - delete newTractor; -} - -int CustomTrackView::getTrackFromPos(double y) const -{ - int totalTracks = m_timeline->tracksCount() - 1; - return qMax(1, totalTracks - ((int)(y / m_tracksHeight))); -} - -int CustomTrackView::getPositionFromTrack(int track) const -{ - int totalTracks = m_timeline->tracksCount() - 1; - return m_tracksHeight * (totalTracks - track); -} - -void CustomTrackView::importPlaylist(const ItemInfo &info, const QMap &idMap, const QDomDocument &doc, QUndoCommand *command) -{ - Mlt::Producer *import = new Mlt::Producer(*m_document->renderer()->getProducer()->profile(), "xml-string", doc.toString().toUtf8().constData()); - if ((import == nullptr) || !import->is_valid()) { - delete command; - qCDebug(KDENLIVE_LOG) << " / / /CANNOT open playlist to import "; - emit displayMessage(i18n("Malformed playlist clip: invalid content."), MltError); - return; - } - Mlt::Service service(import->parent().get_service()); - if (service.type() != tractor_type) { - delete command; - qCDebug(KDENLIVE_LOG) << " / / /CANNOT playlist file: " << service.type(); - emit displayMessage(i18n("Malformed playlist clip: missing tractor."), MltError); - return; - } - - // Parse imported file - Mlt::Tractor tractor(service); - int playlistTracks = tractor.count(); - // (In)sanity check... ;) - if (playlistTracks < 1) { - delete command; - emit displayMessage(i18n("Malformed playlist clip: no tracks."), MltError); - return; - } - // Expansion of a playlist clip is "down": that is, a multi-track playlist - // occupies the tracks at and below the track where the playlist clip is. - // This is in line with how Kdenlive traditionally handles tracks, from - // top to bottom. Remember that the bottommost *user* timeline track has index 1! - int topTrack = info.track; - int bottomTrack = topTrack - playlistTracks + 1; - if (bottomTrack < 1) { - // playlist clip would expand below the timeline, so try to - // shift the playlist clip up onto a higher track. If there is - // room to do so, that is... - // Remember that timeline tracksCount() is the number of timeline tractor - // tracks, so this includes the black track with index 0. Or we just use - // visibleTracksCount() then :) - if (playlistTracks > m_timeline->visibleTracksCount()) { - // There are not enough tracks in the timeline. - qCWarning(KDENLIVE_LOG) << " / / / more playlist tracks than timeline tracks"; - delete command; - emit displayMessage(i18n("Selected playlist clip needs more tracks (%1) than there are tracks in the timeline (%2).", playlistTracks, - m_timeline->visibleTracksCount()), - MltError); - return; - } - topTrack = playlistTracks; - bottomTrack = 1; - } - // Check if there are no objects on the way: the expansion direction - // for multi-track playlists is "down", that is, we occupy additional tracks - // *below* the playlist clip in the timeline. - double startY = getPositionFromTrack(topTrack) + 1; // TODO: check +1 - QRectF r(info.startPos.frames(pCore->getCurrentFps()), startY, (info.endPos - info.startPos).frames(pCore->getCurrentFps()), - m_tracksHeight * playlistTracks); - QList selection = m_scene->items(r); - ClipItem *playlistToExpand = getClipItemAtStart(info.startPos, info.track); - if (playlistToExpand) { - selection.removeAll(playlistToExpand); - } - for (int i = 0; i < selection.count(); ++i) { - QGraphicsItem *item = selection.at(i); - if (item->type() == TransitionWidget || item->type() == AVWidget) { - if (item->type() == TransitionWidget) { - // We allow transitions immediately above the playlist clip (top track) - // to overlap with the playlist clip and don't regard this as a collision. - // The rationale is that any playlist clip cannot have a transition above - // its topmost track, so this is never going to be a collision. Au contraire, - // this improves some workflows incredibly, so we can now place playlist - // clips immediately below a higher track with some overlay logo. - Transition *tr = static_cast(item); - if (tr->track() > topTrack) { - continue; - } - } - qCWarning(KDENLIVE_LOG) << " / / /There are clips in timeline preventing expand actions"; - emit displayMessage( - i18n("Not enough free track space above or below the selected playlist clip: need free room on %1 tracks to expand playlist.", playlistTracks), - MltError); - delete command; - return; - } - } - new RefreshMonitorCommand(this, info, false, true, command); - for (int i = 0; i < playlistTracks; i++) { - int startPos = info.startPos.frames(pCore->getCurrentFps()); - Mlt::Producer trackProducer(tractor.track(i)); - Mlt::Playlist trackPlaylist((mlt_playlist)trackProducer.get_service()); - for (int j = 0; j < trackPlaylist.count(); j++) { - QScopedPointer original(trackPlaylist.get_clip(j)); - if (original == nullptr || !original->is_valid()) { - // invalid clip - continue; - } - if (original->is_blank()) { - startPos += original->get_playtime(); - continue; - } - // Found a producer, import it - QString originalId = original->parent().get("id"); - // track producer - if (originalId.contains(QLatin1Char('_'))) { - originalId = originalId.section(QLatin1Char('_'), 0, 0); - } - // slowmotion producer - if (originalId.contains(QLatin1Char(':'))) { - originalId = originalId.section(QLatin1Char(':'), 1, 1); - } - // TODO: Handle speed effect! - - QString newId = idMap.value(originalId); - qCDebug(KDENLIVE_LOG) << "newId: " << newId << ", originalId: " << originalId; - if (newId.isEmpty()) { - qCDebug(KDENLIVE_LOG) << " / /WARNING, MISSING PRODUCER FOR: " << originalId; - startPos += original->get_playtime(); - continue; - } - // Ready, insert clip - ItemInfo insertInfo; - insertInfo.startPos = GenTime(startPos, pCore->getCurrentFps()); - int in = original->get_in(); - int out = original->get_out(); - insertInfo.cropStart = GenTime(in, pCore->getCurrentFps()); - insertInfo.cropDuration = GenTime(out - in + 1, pCore->getCurrentFps()); - insertInfo.endPos = insertInfo.startPos + insertInfo.cropDuration; - insertInfo.track = bottomTrack + i; - EffectsList effects = ClipController::xmlEffectList(original->profile(), *original); - new AddTimelineClipCommand(this, newId, insertInfo, effects, PlaylistState::Original, true, false, false, command); - startPos += original->get_playtime(); - } - updateTrackDuration(bottomTrack + i, command); - } - - // Paste transitions - QScopedPointer serv(tractor.field()); - while ((serv != nullptr) && serv->is_valid()) { - if (serv->type() == transition_type) { - Mlt::Transition t((mlt_transition)serv->get_service()); - if (t.get_int("internal_added") > 0) { - // This is an auto transition, skip - } else { - Mlt::Properties prop(t.get_properties()); - ItemInfo transitionInfo; - transitionInfo.startPos = info.startPos + GenTime(t.get_in(), pCore->getCurrentFps()); - transitionInfo.endPos = info.startPos + GenTime(t.get_out(), pCore->getCurrentFps()); - transitionInfo.track = t.get_b_track() + bottomTrack; - int endTrack = t.get_a_track() + bottomTrack; - if (prop.get("kdenlive_id") == nullptr && QString(prop.get("mlt_service")) == QLatin1String("composite") && - Timeline::isSlide(prop.get("geometry"))) { - prop.set("kdenlive_id", "slide"); - } - QDomElement base = MainWindow::transitions.getEffectByTag(prop.get("mlt_service"), prop.get("kdenlive_id")).cloneNode().toElement(); - - QDomNodeList params = base.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - QString paramName = e.hasAttribute(QStringLiteral("tag")) ? e.attribute(QStringLiteral("tag")) : e.attribute(QStringLiteral("name")); - QString value; - if (paramName == QLatin1String("a_track")) { - value = QString::number(transitionInfo.track); - } else if (paramName == QLatin1String("b_track")) { - value = QString::number(endTrack); - } else { - value = prop.get(paramName.toUtf8().constData()); - } - // int factor = e.attribute("factor").toInt(); - if (value.isEmpty()) { - continue; - } - e.setAttribute(QStringLiteral("value"), value); - } - base.setAttribute(QStringLiteral("force_track"), prop.get_int("force_track")); - base.setAttribute(QStringLiteral("automatic"), prop.get_int("automatic")); - new AddTransitionCommand(this, transitionInfo, endTrack, base, false, true, command); - } - } - serv.reset(serv->producer()); - } - - if (command->childCount() > 0) { - new RefreshMonitorCommand(this, info, true, false, command); - m_commandStack->push(command); - } else { - delete command; - } -} - -void CustomTrackView::updateTransitionWidget(Transition *tr, const ItemInfo &info) -{ - QPoint p; - ClipItem *transitionClip = getClipItemAtStart(info.startPos, info.track); - if ((transitionClip != nullptr) && (transitionClip->binClip() != nullptr)) { - int frameWidth = transitionClip->binClip()->getProducerIntProperty(QStringLiteral("meta.media.width")); - int frameHeight = transitionClip->binClip()->getProducerIntProperty(QStringLiteral("meta.media.height")); - double factor = transitionClip->binClip()->getProducerProperty(QStringLiteral("aspect_ratio")).toDouble(); - if (factor == 0) { - factor = 1.0; - } - p.setX((int)(frameWidth * factor + 0.5)); - p.setY(frameHeight); - } - emit transitionItemSelected(tr, getPreviousVideoTrack(tr->track()), p, true); -} - -void CustomTrackView::dropTransitionGeometry(Transition *trans, const QString &geometry) -{ - if ((m_dragItem == nullptr) || m_dragItem != trans) { - clearSelection(false); - m_dragItem = trans; - m_dragItem->setMainSelectedClip(true); - trans->setSelected(true); - updateTimelineSelection(); - } - emit transitionItemSelected(trans); - QMap keyframes; - keyframes.insert(i18n("Dropped Geometry"), geometry); - slotImportClipKeyframes(TransitionWidget, trans->info(), trans->toXML(), keyframes); -} - -void CustomTrackView::dropClipGeometry(ClipItem *clip, const QString &geometry) -{ - if ((m_dragItem == nullptr) || m_dragItem != clip) { - clearSelection(false); - m_dragItem = clip; - m_dragItem->setMainSelectedClip(true); - clip->setSelected(true); - updateTimelineSelection(); - } - emit clipItemSelected(clip); - if (geometry.isEmpty()) { - emit displayMessage(i18n("No keyframes to import"), InformationMessage); - return; - } - QMap keyframes; - keyframes.insert(geometry.section(QLatin1Char('='), 0, 0), geometry.section(QLatin1Char('='), 1)); - QDomElement currentEffect = clip->getEffectAtIndex(clip->selectedEffectIndex()); - if (currentEffect.isNull()) { - emit displayMessage(i18n("No effect to import keyframes"), InformationMessage); - return; - } - slotImportClipKeyframes(AVWidget, clip->info(), currentEffect.cloneNode().toElement(), keyframes); -} - -void CustomTrackView::breakLockedGroups(const QList &clipsToMove, const QList &transitionsToMove, QUndoCommand *masterCommand, bool doIt) -{ - QList processedGroups; - for (int i = 0; i < clipsToMove.count(); ++i) { - ClipItem *clip = getClipItemAtStart(clipsToMove.at(i).startPos, clipsToMove.at(i).track); - if (clip == nullptr || (clip->parentItem() == nullptr)) { - qCDebug(KDENLIVE_LOG) << " * ** Canot find clip to break: " << clipsToMove.at(i).startPos.frames(25) << ", " << clipsToMove.at(i).track; - continue; - } - // If group has a locked item, ungroup first - AbstractGroupItem *grp = static_cast(clip->parentItem()); - if (grp->isItemLocked() && !processedGroups.contains(grp)) { - processedGroups << grp; - groupClips(false, grp->childItems(), true, masterCommand, doIt); - } - } - for (int i = 0; i < transitionsToMove.count(); ++i) { - Transition *trans = getTransitionItemAtStart(transitionsToMove.at(i).startPos, transitionsToMove.at(i).track); - if (trans == nullptr || (trans->parentItem() == nullptr)) { - continue; - } - // If group has a locked item, ungroup first - AbstractGroupItem *grp = static_cast(trans->parentItem()); - if (grp->isItemLocked() && !processedGroups.contains(grp)) { - processedGroups << grp; - groupClips(false, grp->childItems(), true, masterCommand, doIt); - } - } -} - -void CustomTrackView::switchTrackLock() -{ - slotSwitchTrackLock(m_selectedTrack, !m_timeline->getTrackInfo(m_selectedTrack).isLocked); -} - -void CustomTrackView::switchAllTrackLock() -{ - if (m_selectedTrack > 1) { - slotSwitchTrackLock(m_selectedTrack, !m_timeline->getTrackInfo(1).isLocked, true); - } else if (m_timeline->visibleTracksCount() > 1) { - slotSwitchTrackLock(m_selectedTrack, !m_timeline->getTrackInfo(2).isLocked, true); - } -} - -void CustomTrackView::slotAcceptRipple(bool) -{ - QMetaObject::invokeMethod(this, "switchTrimMode", Qt::QueuedConnection); - /*TrimManager *mgr = qobject_cast(m_toolManagers.value(TrimType)); - if (mgr) - - }*/ -} - -void CustomTrackView::doRipple(bool accept) -{ - if (accept) { - auto *command = new QUndoCommand; - command->setText(i18n("Ripple Edit")); - ItemInfo info = m_dragItem->info(); - int resizePos = m_cursorPos; - // Ripple clip start - ClipItem *second = getClipItemAtEnd(info.startPos, info.track); // - GenTime(1, pCore->getCurrentFps()), info.track); - if (!second) { - // Something is wrong - qCDebug(KDENLIVE_LOG) << " * * ** CAMNNOT FIND SECONT CLIP"; - emit displayMessage(i18n("Cannot find clip"), InformationMessage); - monitorRefresh(); - QTimer::singleShot(0, this, SLOT(resetScene())); - return; - } - ItemInfo secondInfo = second->info(); - if (resizePos > info.startPos.frames(pCore->getCurrentFps())) { - // shortening target clip, resize selected clip first - prepareResizeClipStart(m_dragItem, info, resizePos, true, command); - prepareResizeClipEnd(second, secondInfo, resizePos, true, command); - } else { - prepareResizeClipEnd(second, secondInfo, resizePos, true, command); - prepareResizeClipStart(m_dragItem, info, resizePos, true, command); - } - m_commandStack->push(command); - } - monitorRefresh(); - emit loadMonitorScene(MonitorSceneDefault, false); -} - -void CustomTrackView::setOperationMode(OperationType mode) -{ - m_moveOpMode = mode; -} - -OperationType CustomTrackView::prepareMode() const -{ - return m_operationMode; -} - -OperationType CustomTrackView::operationMode() const -{ - return m_moveOpMode; -} - -AbstractClipItem *CustomTrackView::dragItem() -{ - return m_dragItem; -} - -AbstractGroupItem *CustomTrackView::selectionGroup() -{ - AbstractGroupItem *group = nullptr; - if (m_selectionGroup) { - group = static_cast(m_selectionGroup); - } else if (m_dragItem) { - group = static_cast(m_dragItem->parentItem()); - } - return group; -} - -TimelineMode::EditMode CustomTrackView::sceneEditMode() -{ - return m_scene->editMode(); -} - -bool CustomTrackView::isLastClip(const ItemInfo &info) -{ - return m_timeline->isLastClip(info); -} - -TrackInfo CustomTrackView::getTrackInfo(int ix) -{ - return m_timeline->getTrackInfo(ix); -} - -Timecode CustomTrackView::timecode() -{ - return m_document->timecode(); -} - -void CustomTrackView::reloadTrack(const ItemInfo &info, bool includeLastFrame) -{ - m_timeline->reloadTrack(info, includeLastFrame); -} - -void CustomTrackView::sortGuides() -{ - qSort(m_guides.begin(), m_guides.end(), sortGuidesList); -} - -void CustomTrackView::switchTrimMode(int mode) -{ - switchTrimMode((TrimMode)mode); -} - -void CustomTrackView::switchTrimMode(TrimMode mode) -{ - TrimManager *mgr = qobject_cast(m_toolManagers.value(AbstractToolManager::TrimType)); - if (mode == NormalTrim) { - mode = (TrimMode)(qMax(((int)mgr->trimMode() + 1) % 5, 1)); - } - // Find best clip to trim - ItemInfo info; - // TODO: if cursor is not on a cut, switch only between slip and slide - AbstractClipItem *trimItem = nullptr; - if ((m_dragItem != nullptr) && m_dragItem->type() == AVWidget) { - trimItem = m_dragItem; - } else { - // find topmost clip - trimItem = getUpperClipItemAt(m_cursorPos); - if (trimItem) { - slotSelectItem(trimItem); - } - } - if (trimItem) { - info = trimItem->info(); - GenTime cursor(m_cursorPos, pCore->getCurrentFps()); - if (cursor == info.startPos) { - // Start trim at clip start - mgr->setTrimMode(mode, info, true); - } else if (cursor == info.endPos) { - // Start trim at clip end - mgr->setTrimMode(mode, info, false); - } else { - int diffStart = qAbs(m_cursorPos - info.startPos.frames(pCore->getCurrentFps())); - int diffEnd = qAbs(m_cursorPos - info.endPos.frames(pCore->getCurrentFps())); - mgr->setTrimMode(mode, info, diffStart < diffEnd); - } - } -} - -bool CustomTrackView::rippleClip(ClipItem *clip, int diff) -{ - GenTime timeOffset(diff, pCore->getCurrentFps()); - if (clip->cropDuration() + timeOffset > clip->maxDuration()) { - emit displayMessage(i18n("Maximum length reached"), InformationMessage); - return false; - } - QList selection; - spaceToolSelectTrackOnly(clip->track(), selection, clip->endPos()); - createGroupForSelectedItems(selection); - QList items; - for (QGraphicsItem *item : selection) { - if (item->type() == AVWidget || item->type() == TransitionWidget) { - items << (AbstractClipItem *)item; - } - } - bool snap = KdenliveSettings::snaptopoints(); - KdenliveSettings::setSnaptopoints(false); - QList excluded; - excluded << clip; - if (canBePasted(items, timeOffset, 0, excluded)) { - m_selectionGroup->setTransform(QTransform::fromTranslate(diff, 0), true); - clip->setCropStart(clip->cropStart() - GenTime(diff, pCore->getCurrentFps())); - clip->resizeEnd(clip->endPos().frames(pCore->getCurrentFps()) + diff, false); - qCDebug(KDENLIVE_LOG) << "* * *RESIZING END: " << clip->endPos().frames(pCore->getCurrentFps()) + diff; - } else { - // TODO: corruption, cannot move - } - /*if (diff > 0) { - for (int i = 0; i < list - m_view-> - m_secondClip->resizeStart(pos, true, false); - m_firstClip->resizeEnd(pos, false); - } else { - m_secondClip->resizeStart(pos, true, false); - }*/ - KdenliveSettings::setSnaptopoints(snap); - return true; -} - -void CustomTrackView::finishRipple(ClipItem *clip, const ItemInfo &startInfo, int diff, bool fromStart) -{ - auto *moveCommand = new QUndoCommand(); - moveCommand->setText(i18n("Ripple clip")); - ItemInfo newInfo = clip->info(); - if (fromStart) { - // newInfo.cropStart += GenTime(diff, pCore->getCurrentFps()); - } - qCDebug(KDENLIVE_LOG) << "CROPSATRT: " << startInfo.cropStart.frames(25) << " / " << newInfo.cropStart.frames(25); - new ResizeClipCommand(this, startInfo, newInfo, false, false, moveCommand); - m_commandStack->push(moveCommand); - if (m_timeline->track(startInfo.track) - ->resize_in_out(startInfo.startPos.frames(pCore->getCurrentFps()), clip->cropStart().frames(pCore->getCurrentFps()), - clip->cropStart().frames(pCore->getCurrentFps()) + clip->cropDuration().frames(pCore->getCurrentFps()))) - // resizeClip(startInfo, clip->info(), true); - { - qCDebug(KDENLIVE_LOG) << "* * *RESIZING CLIP: " << diff << ", FROM START: " << fromStart; - } -} diff --git a/src/timeline/customtrackview.h b/src/timeline/customtrackview.h deleted file mode 100644 index 403ccef53..000000000 --- a/src/timeline/customtrackview.h +++ /dev/null @@ -1,631 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef CUSTOMTRACKVIEW_H -#define CUSTOMTRACKVIEW_H - -#include - -#include -#include -#include -#include -#include -#include - -#include "doc/kdenlivedoc.h" -#include "effectslist/effectslist.h" -#include "timeline/customtrackscene.h" -#include "timeline/guide.h" -#include "timeline/managers/abstracttoolmanager.h" - -class Timeline; -class ClipController; -class ClipItem; -class AbstractClipItem; -class AbstractGroupItem; -class Transition; -class AudioCorrelation; -class KSelectAction; - -class CustomTrackView : public QGraphicsView -{ - Q_OBJECT - -public: - CustomTrackView(KdenliveDoc *doc, Timeline *timeline, CustomTrackScene *projectscene, QWidget *parent = nullptr); - virtual ~CustomTrackView(); - - void mousePressEvent(QMouseEvent *event) override; - void mouseReleaseEvent(QMouseEvent *event) override; - void mouseMoveEvent(QMouseEvent *event) override; - void mouseDoubleClickEvent(QMouseEvent *event) override; - void addTrack(const TrackInfo &type, int ix = -1); - void removeTrack(int ix); - /** @brief Makes the document use new track info (name, type, ...). */ - void configTracks(const QList &trackInfos); - int cursorPos() const; - void checkAutoScroll(); - /** - Move the clip at \c start to \c end. - - If \c out_actualEnd is not nullptr, it will be set to the position the clip really ended up at. - For example, attempting to move a clip to t = -1 s will actually move it to t = 0 s. - */ - bool moveClip(const ItemInfo &start, const ItemInfo &end, bool refresh, bool alreadyMoved, ItemInfo *out_actualEnd = nullptr); - void moveGroup(QList startClip, QList startTransition, const GenTime &offset, const int trackOffset, bool alreadyMoved, - bool reverseMove); - /** move transition, startPos = (old start, old end), endPos = (new start, new end) */ - void moveTransition(const ItemInfo &start, const ItemInfo &end, bool refresh); - void resizeClip(const ItemInfo &start, const ItemInfo &end, bool dontWorry = false); - void addClip(const QString &clipId, const ItemInfo &info, const EffectsList &list, PlaylistState::ClipState state, bool refresh = true); - void deleteClip(const ItemInfo &info, bool refresh = true); - void addMarker(const QString &id, const CommentedTime &marker); - void addData(const QString &id, const QString &key, const QString &data); - void setScale(double scaleFactor, double verticalScale, bool zoomOnMouse = false); - void deleteClip(const QString &clipId, QUndoCommand *deleteCommand); - /** @brief An effect was dropped on @param clip */ - void slotDropEffect(ClipItem *clip, const QDomElement &effect, GenTime pos, int track); - /** @brief A transition was dropped on @param clip */ - void slotDropTransition(ClipItem *clip, const QDomElement &transition, QPointF scenePos); - /** @brief Add effect to current clip */ - void slotAddEffectToCurrentItem(const QDomElement &effect); - /** @brief Add effect to a clip or selection */ - void slotAddEffect(const QDomElement &effect, const GenTime &pos, int track); - void slotAddGroupEffect(const QDomElement &effect, AbstractGroupItem *group, AbstractClipItem *dropTarget = nullptr); - void addEffect(int track, GenTime pos, const QDomElement &effect); - void deleteEffect(int track, const GenTime &pos, const QDomElement &effect); - void updateEffect(int track, GenTime pos, const QDomElement &insertedEffect, bool refreshEffectStack = false, bool replaceEffect = false, - bool refreshMonitor = true); - /** @brief Enable / disable a list of effects */ - void updateEffectState(int track, GenTime pos, const QList &effectIndexes, bool disable, bool updateEffectStack); - void moveEffect(int track, const GenTime &pos, const QList &oldPos, const QList &newPos); - void addTransition(const ItemInfo &transitionInfo, int endTrack, const QDomElement ¶ms, bool refresh); - void deleteTransition(const ItemInfo &transitionInfo, int endTrack, const QDomElement ¶ms, bool refresh); - void updateTransition(int track, const GenTime &pos, const QDomElement &oldTransition, const QDomElement &transition, bool updateTransitionWidget); - void activateMonitor(); - int duration() const; - void deleteSelectedClips(); - /** @brief Cuts all clips that are selected at the timeline cursor position. */ - void cutSelectedClips(QList itemList = QList(), GenTime currentPos = GenTime()); - void setContextMenu(QMenu *timeline, QMenu *clip, QMenu *transition, QActionGroup *clipTypeGroup, QMenu *markermenu); - bool checkTrackHeight(bool force = false); - void updateSceneFrameWidth(double fpsChanged = 1.0); - void setTool(ProjectTool tool); - void cutClip(const ItemInfo &info, const GenTime &cutTime, bool cut, const EffectsList &oldStack = EffectsList(), bool execute = true); - Transition *cutTransition(const ItemInfo &info, const GenTime &cutTime, bool cut, const QDomElement &oldStack = QDomElement(), bool execute = true); - void slotSeekToPreviousSnap(); - void slotSeekToNextSnap(); - double getSnapPointForPos(double pos); - bool findString(const QString &text); - void selectFound(const QString &track, const QString &pos); - bool findNextString(const QString &text); - void initSearchStrings(); - void clearSearchStrings(); - QList findId(const QString &clipId); - void clipStart(); - void clipEnd(); - void doChangeClipSpeed(const ItemInfo &info, const ItemInfo &speedIndependantInfo, PlaylistState::ClipState state, const double speed, int strobe, - const QString &id, bool removeEffect = false); - /** @brief Every command added to the undo stack automatically triggers a document change event. - * This function should only be called when changing a document setting or another function that - * is not integrated in the undo / redo system */ - void setDocumentModified(); - void setInPoint(); - void setOutPoint(); - - /** @brief Prepares inserting space. - * - * Shows a dialog to configure length and track. */ - void slotInsertSpace(); - /** @brief Prepares removing space. */ - void slotRemoveSpace(bool multiTrack = false); - void insertSpace(const QList &clipsToMove, const QList &transToMove, int track, const GenTime &duration, const GenTime &offset); - ClipItem *getActiveClipUnderCursor(bool allowOutsideCursor = false) const; - void deleteTimelineTrack(int ix, const TrackInfo &trackinfo); - void saveThumbnails(); - void autoTransition(); - void initCursorPos(int pos); - - /** @brief Locks or unlocks a track. - * @param ix number of track - * @param lock whether to lock or unlock - * @param requestUpdate (default = true) Whether to request an update of the icon in the track header - * - * Makes sure no clip on track to lock is selected. */ - void lockTrack(int ix, bool lock, bool requestUpdate = true); - void groupClips(bool group = true, QList itemList = QList(), bool forceLock = false, QUndoCommand *command = nullptr, - bool doIt = true); - void doGroupClips(const QList &clipInfos, const QList &transitionInfos, bool group); - void loadGroups(const QDomNodeList &groups); - - /** @brief Creates SplitAudioCommands for selected clips. */ - void splitAudio(bool warn = true, const ItemInfo &info = ItemInfo(), int destTrack = -1, QUndoCommand *masterCommand = nullptr); - - /// Define which clip to take as reference for automatic audio alignment - void setAudioAlignReference(); - - /// Automatically align the currently selected clips to synchronize their audio with the reference's audio - void alignAudio(); - - /** @brief Separates the audio of a clip to a audio track. - * @param pos Position of the clip to split - * @param track Track of the clip - * @param split Split or unsplit - * @return true if the split was successful */ - bool doSplitAudio(const GenTime &pos, int track, int destTrack, bool split); - /** @brief Sets the clip type (av, video only, audio only) of the current selection. */ - void setClipType(PlaylistState::ClipState state); - void doChangeClipType(const ItemInfo &info, PlaylistState::ClipState state); - /** @brief Check if there is a guide at position. - * @param pos Position to check - * @param framePos If set to true, pos is an exact frame number, otherwise it's a mouse event pos - */ - int hasGuide(double pos, bool framePos); - void reloadTransitionLumas(); - void updateProjectFps(); - double fps() const; - int selectedTrack() const; - QStringList selectedClips() const; - /** @brief Checks whether an item can be inserted (make sure it does not overlap another item) */ - bool canBePastedTo(const ItemInfo &info, int type, const QList &excluded = QList()) const; - - /** @brief Selects a clip. - * @param add Whether to select or deselect - * @param group (optional) Whether to add the clip to a group - * @param track (optional) The track of the clip (has to be combined with @param pos) - * @param pos (optional) The position of the clip (has to be combined with @param track) */ - void selectClip(bool add, bool group = false, int track = -1, int pos = -1); - void selectTransition(bool add, bool group = false); - QStringList extractTransitionsLumas(); - void setEditMode(TimelineMode::EditMode mode); - - /** @brief Inserts @param clip. - * @param clip The clip to insert - * @param in The inpoint of the clip (crop from start) - * @param out The outpoint of the clip (crop from end) - * - * Inserts at the position of timeline cursor and selected track. */ - void insertClipCut(const QString &id, int in, int out); - void clearSelection(bool emitInfo = true); - void editItemDuration(); - void buildGuidesMenu(QMenu *goMenu) const; - /** update the timeline objects when palette changes */ - void updatePalette(); - /** @brief Returns true if a track has audio data on it. - * @param track The track number - * - * Check whether given track has a clip with audio in it. */ - bool hasAudio(int track) const; - - int getFrameWidth() const; - /** @brief Returns last requested seeking pos, or current cursor position. */ - int seekPosition() const; - - void monitorRefresh(bool invalidateRange = false); - /** @brief Trigger a monitor refresh if timeline cursor is inside range. */ - void monitorRefresh(const ItemInfo &range, bool invalidateRange = false); - - /** @brief Returns frame number of current mouse position. */ - int getMousePos() const; - /** @brief Insert space in timeline after clips were moved. if fromstart is true, we assume clips have not yet been moved manually. */ - void completeSpaceOperation(int track, GenTime &timeOffset, bool fromStart = false); - void spaceToolMoveToSnapPos(double snappedPos); - void createRectangleSelection(Qt::KeyboardModifiers modifiers); - int spaceToolSelectTrackOnly(int track, QList &selection, GenTime pos = GenTime(-1)); - QList selectAllItemsToTheRight(int x); - GenTime createGroupForSelectedItems(QList &selection); - void resetSelectionGroup(bool selectItems = true); - /** @brief Returns all infos necessary to save guides. */ - QMap guidesData() const; - /** @brief Reset scroll bar to 0. */ - void scrollToStart(); - /** @brief Returns a track index (in MLT values) from an y position in timeline. */ - int getTrackFromPos(double y) const; - /** @brief Returns customtrackview y position from an MLT track number. */ - int getPositionFromTrack(int track) const; - /** @brief Expand current timeline clip (recover clips and tracks from an MLT playlist) */ - void expandActiveClip(); - /** @brief Import amultitrack MLT playlist in timeline */ - void importPlaylist(const ItemInfo &info, const QMap &idMap, const QDomDocument &doc, QUndoCommand *command); - /** @brief Returns true if there is a selected item in timeline */ - bool hasSelection() const; - /** @brief Get the index of the video track that is just above current track */ - int getNextVideoTrack(int track); - /** @brief returns id of clip under cursor and set pos to cursor position in clip, - * zone gets in/out points */ - const QString getClipUnderCursor(int *pos, QPoint *zone = nullptr) const; - /** @brief returns displayable timecode info */ - QString getDisplayTimecode(const GenTime &time) const; - QString getDisplayTimecodeFromFrames(int frames) const; - /** @brief Call the default QGraphicsView mouse event */ - void graphicsViewMouseEvent(QMouseEvent *event); - /** @brief Creates an overlay track with filtered clip */ - bool createSplitOverlay(Mlt::Filter *filter); - void removeSplitOverlay(); - /** @brief Geometry keyframes dropped on a transition, start import */ - void dropTransitionGeometry(Transition *trans, const QString &geometry); - /** @brief Geometry keyframes dropped on a clip, start import */ - void dropClipGeometry(ClipItem *trans, const QString &geometry); - /** @brief Switch current track lock state */ - void switchTrackLock(); - void switchAllTrackLock(); - /** @brief Insert space in timeline. track = -1 means all tracks */ - void insertTimelineSpace(GenTime startPos, GenTime duration, int track = -1, const QList &excludeList = QList()); - void trimMode(bool enable, int ripplePos = -1); - /** @brief Returns a clip from timeline - * @param pos the end time position - * @param track the track where the clip is in MLT coordinates */ - ClipItem *getClipItemAtEnd(GenTime pos, int track); - /** @brief Returns a clip from timeline - * @param pos the time position - * @param track the track where the clip is in MLT coordinates - * @param end the end position of the clip in case of overlapping clips (overwrite mode) */ - ClipItem *getClipItemAtStart(GenTime pos, int track, GenTime end = GenTime()); - /** @brief Takes care of updating effects and attached transitions during a resize from start. - * @param item Item to resize - * @param oldInfo The item's info before resizement (set to item->info() is @param check true) - * @param pos New startPos - * @param check (optional, default = false) Whether to check for collisions - * @param command (optional) Will be used as parent command (for undo history) */ - void prepareResizeClipStart(AbstractClipItem *item, const ItemInfo &oldInfo, int pos, bool check = false, QUndoCommand *command = nullptr); - - /** @brief Takes care of updating effects and attached transitions during a resize from end. - * @param item Item to resize - * @param oldInfo The item's info before resizement (set to item->info() is @param check true) - * @param pos New endPos - * @param check (optional, default = false) Whether to check for collisions - * @param command (optional) Will be used as parent command (for undo history) */ - void prepareResizeClipEnd(AbstractClipItem *item, const ItemInfo &oldInfo, int pos, bool check = false, QUndoCommand *command = nullptr); - AbstractClipItem *dragItem(); - /** @brief Cut clips in all non locked tracks. */ - void cutTimeline(int cutPos, const QList &excludedClips, const QList &excludedTransitions, QUndoCommand *masterCommand, int track = -1); - void updateClipTypeActions(ClipItem *clip); - void setOperationMode(OperationType mode); - OperationType operationMode() const; - OperationType prepareMode() const; - TimelineMode::EditMode sceneEditMode(); - bool isLastClip(const ItemInfo &info); - TrackInfo getTrackInfo(int ix); - Transition *getTransitionItemAtStart(GenTime pos, int track); - Transition *getTransitionItemAtEnd(GenTime pos, int track); - void adjustTimelineTransitions(TimelineMode::EditMode mode, Transition *item, QUndoCommand *command); - /** @brief Get the index of the video track that is just below current track */ - int getPreviousVideoTrack(int track); - /** @brief Updates the duration stored in a track's TrackInfo. - * @param track Number of track as used in ItemInfo (not the numbering used in KdenliveDoc) (negative for all tracks) - * @param command If effects need to be updated the commands to do this will be attached to this undo command - * - * In addition to update the duration in TrackInfo it updates effects with keyframes on the track. */ - void updateTrackDuration(int track, QUndoCommand *command); - /** @brief Send updtaed info to transition widget. */ - void updateTransitionWidget(Transition *tr, const ItemInfo &info); - AbstractGroupItem *selectionGroup(); - Timecode timecode(); - /** @brief Collects information about the group's children to pass it on to RazorGroupCommand. - * @param group The group to cut - * @param cutPos The absolute position of the cut */ - void razorGroup(AbstractGroupItem *group, GenTime cutPos); - void reloadTrack(const ItemInfo &info, bool includeLastFrame); - GenTime groupSelectedItems(QList selection = QList(), bool createNewGroup = false, bool selectNewGroup = false); - void sortGuides(); - void initTools(); - AbstractToolManager *toolManager(AbstractToolManager::ToolManagerType trimType); - /** @brief Perform a ripple move on timeline clips */ - bool rippleClip(ClipItem *clip, int diff); - void finishRipple(ClipItem *clip, const ItemInfo &startInfo, int diff, bool fromStart); - -public slots: - /** @brief Send seek request to MLT. */ - void seekCursorPos(int pos); - /** @brief Move timeline cursor to new position. */ - void setCursorPos(int pos); - void moveCursorPos(int delta); - void slotDeleteEffectGroup(ClipItem *clip, int track, const QDomDocument &doc, bool affectGroup = true); - void slotDeleteEffect(ClipItem *clip, int track, const QDomElement &effect, bool affectGroup = true, QUndoCommand *parentCommand = nullptr); - void slotChangeEffectState(ClipItem *clip, int track, QList effectIndexes, bool disable); - void slotChangeEffectPosition(ClipItem *clip, int track, const QList ¤tPos, int newPos); - void slotUpdateClipEffect(ClipItem *clip, int track, const QDomElement &oldeffect, const QDomElement &effect, int ix, bool refreshEffectStack = true); - void slotUpdateClipRegion(ClipItem *clip, int ix, const QString ®ion); - void slotRefreshEffects(ClipItem *clip); - void setDuration(int duration); - void slotAddTransition(ClipItem *clip, const ItemInfo &transitionInfo, int endTrack, const QDomElement &transition = QDomElement()); - void slotAddTransitionToSelectedClips(const QDomElement &transition, QList itemList = QList()); - void slotTransitionUpdated(Transition *, const QDomElement &); - void slotSwitchTrackLock(int ix, bool enable, bool applyToAll = false); - void slotUpdateClip(const QString &clipId, bool reload = true); - - bool addGuide(const GenTime &pos, const QString &comment, bool loadingProject = false); - - /** @brief Shows a dialog for adding a guide. - * @param dialog (default = true) false = do not show the dialog but use current position as position and comment */ - void slotAddGuide(bool dialog = true); - void slotEditGuide(const CommentedTime &guide); - void slotEditGuide(int guidePos = -1, const QString &newText = QString()); - void slotDeleteGuide(int guidePos = -1); - void slotDeleteAllGuides(); - void editGuide(const GenTime &oldPos, const GenTime &pos, const QString &comment); - void copyClip(); - void pasteClip(); - void pasteClipEffects(); - void slotUpdateAllThumbs(); - void slotCheckPositionScrolling(); - void slotInsertTrack(int ix); - /** @brief Trigger a monitor refresh. */ - void monitorRefresh(const QList &range, bool invalidateRange = false); - - /** @brief Shows a dialog for selecting a track to delete. - * @param ix Number of the track, which should be pre-selected in the dialog */ - void slotDeleteTrack(int ix); - /** @brief Shows the configure tracks dialog. */ - void slotConfigTracks(int ix); - void clipNameChanged(const QString &id); - void slotSelectTrack(int ix, bool switchTarget = false); - int insertZone(TimelineMode::EditMode sceneMode, const QString &clipId, QPoint binZone); - - /** @brief Rebuilds a group to fit again after children changed. - * @param childTrack the track of one of the groups children - * @param childPos The position of the same child */ - void rebuildGroup(int childTrack, const GenTime &childPos); - /** @brief Rebuilds a group to fit again after children changed. - * @param group The group to rebuild */ - void rebuildGroup(AbstractGroupItem *group); - - /** @brief Add en effect to a track. - * @param effect The new effect xml - * @param ix The track index */ - void slotAddTrackEffect(const QDomElement &effect, int ix); - /** @brief Select all clips in selected track. */ - void slotSelectClipsInTrack(); - /** @brief Select all clips in timeline. */ - void slotSelectAllClips(); - - /** @brief Update the list of snap points (sticky timeline hotspots). - * @param selected The currently selected clip if any - * @param offsetList The list of points that should also snap (for example when movin a clip, start and end points should snap - * @param skipSelectedItems if true, the selected item start and end points will not be added to snap list */ - void updateSnapPoints(AbstractClipItem *selected, const QList &offsetList = QList(), bool skipSelectedItems = false); - - void slotAddEffect(ClipItem *clip, const QDomElement &effect, int track = -1); - void slotImportClipKeyframes(GraphicsRectItem type, const ItemInfo &info, const QDomElement &xml, - QMap keyframes = QMap()); - - /** @brief Move playhead to mouse curser position if defined key is pressed */ - void slotAlignPlayheadToMousePos(); - - void slotInfoProcessingFinished(); - void slotAlignClip(int, int, int); - /** @brief Export part of the playlist in an xml file */ - void exportTimelineSelection(QString path = QString()); - /** Remove zone from current track */ - void extractZone(QPoint z, bool closeGap, const QList &excludedClips = QList(), QUndoCommand *masterCommand = nullptr, int track = -1); - /** @brief Select an item in timeline. */ - void slotSelectItem(AbstractClipItem *item); - /** @brief Cycle through timeline trim modes */ - void switchTrimMode(TrimMode mode = NormalTrim); - void switchTrimMode(int mode); - -protected: - void drawBackground(QPainter *painter, const QRectF &rect) override; - // virtual void drawForeground ( QPainter * painter, const QRectF & rect ); - void dragEnterEvent(QDragEnterEvent *event) override; - void dragMoveEvent(QDragMoveEvent *event) override; - void dragLeaveEvent(QDragLeaveEvent *event) override; - bool event(QEvent *e) override; - /** @brief Something has been dropped onto the timeline */ - void dropEvent(QDropEvent *event) override; - void enterEvent(QEvent *event) override; - void leaveEvent(QEvent *event) override; - void wheelEvent(QWheelEvent *e) override; - void keyPressEvent(QKeyEvent *event) override; - virtual QStringList mimeTypes() const; - virtual Qt::DropActions supportedDropActions() const; - void contextMenuEvent(QContextMenuEvent *event) override; - -private: - int m_ct; - int m_tracksHeight; - int m_projectDuration; - int m_cursorPos; - double m_cursorOffset; - KdenliveDoc *m_document; - Timeline *m_timeline; - CustomTrackScene *m_scene; - QGraphicsLineItem *m_cursorLine; - ItemInfo m_dragItemInfo; - ItemInfo m_selectionGroupInfo; - /** @brief Possible timeline action */ - OperationType m_operationMode; - /** @brief Currently running operation */ - OperationType m_moveOpMode; - AbstractClipItem *m_dragItem; - Guide *m_dragGuide; - std::shared_ptr m_commandStack; - QGraphicsItem *m_visualTip; - QGraphicsItemAnimation *m_keyProperties; - QTimeLine *m_keyPropertiesTimer; - QColor m_tipColor; - QPen m_tipPen; - QPoint m_clickEvent; - QList m_searchPoints; - QList m_guides; - QColor m_selectedTrackColor; - QColor m_lockedTrackColor; - QMap m_toolManagers; - AbstractToolManager *m_currentToolManager; - - /** @brief Returns a clip from timeline - * @param pos a time value that is inside the clip - * @param track the track where the clip is in MLT coordinates */ - ClipItem *getClipItemAtMiddlePoint(int pos, int track); - /** @brief Returns the higher clip at pos on the timeline - * @param pos a time value that is inside the clip */ - ClipItem *getUpperClipItemAt(int pos); - /** @brief Returns a moved clip from timeline (means that the item was moved but its ItemInfo coordinates have not been updated yet) - * */ - ClipItem *getMovedClipItem(const ItemInfo &info, GenTime offset, int trackOffset); - /** @brief Returns a transition from timeline - * @param pos a time value that is inside the clip - * @param track the track where the clip is in MLT coordinates */ - Transition *getTransitionItemAt(int pos, int track, bool alreadyMoved = false); - Transition *getTransitionItemAt(GenTime pos, int track, bool alreadyMoved = false); - void checkScrolling(); - /** Should we auto scroll while playing (keep in sync with KdenliveSettings::autoscroll() */ - bool m_autoScroll; - void displayContextMenu(QPoint pos, AbstractClipItem *clip); - void displayKeyframesMenu(QPoint pos, AbstractClipItem *clip); - QMenu *m_timelineContextMenu; - QMenu *m_timelineContextClipMenu; - QMenu *m_timelineContextTransitionMenu; - QMenu *m_timelineContextKeyframeMenu; - KSelectAction *m_selectKeyframeType; - QAction *m_attachKeyframeToEnd; - QMenu *m_markerMenu; - QAction *m_autoTransition; - QAction *m_pasteEffectsAction; - QAction *m_ungroupAction; - QAction *m_disableClipAction; - QAction *m_editGuide; - QAction *m_deleteGuide; - QList m_audioActions; - QList m_avActions; - QActionGroup *m_clipTypeGroup; - bool m_clipDrag; - - int m_findIndex; - ProjectTool m_tool; - QCursor m_razorCursor; - /** list containing items currently copied in the timeline */ - QList m_copiedItems; - /** Used to get the point in timeline where a context menu was opened */ - QPoint m_menuPosition; - AbstractGroupItem *m_selectionGroup; - int m_selectedTrack; - - QMutex m_selectionMutex; - QMutex m_mutex; - QWaitCondition m_producerNotReady; - - AudioCorrelation *m_audioCorrelator; - ClipItem *m_audioAlignmentReference; - - void updatePositionEffects(ClipItem *item, const ItemInfo &info, bool standalone = true); - bool insertDropClips(const QMimeData *mimeData, const QPoint &pos); - bool canBePastedTo(const QList &infoList, int type) const; - bool canBePasted(const QList &items, GenTime offset, int trackOffset, - QList excluded = QList()) const; - ClipItem *getClipUnderCursor() const; - AbstractClipItem *getMainActiveClip() const; - /** Get available space for clip move (min and max free positions) */ - void getClipAvailableSpace(AbstractClipItem *item, GenTime &minimum, GenTime &maximum); - /** Get available space for transition move (min and max free positions) */ - void getTransitionAvailableSpace(AbstractClipItem *item, GenTime &minimum, GenTime &maximum); - /** Whether an item can be moved to a new position without colliding with similar items */ - bool itemCollision(AbstractClipItem *item, const ItemInfo &newPos); - /** Selects all items in the scene rect, and sets ok to false if a group going over several tracks is found in it */ - QList checkForGroups(const QRectF &rect, bool *ok); - /** Adjust keyframes when pasted to another clip */ - void adjustKeyfames(GenTime oldstart, GenTime newstart, GenTime duration, QDomElement xml); - - /** @brief Removes the tip and stops the animation timer. */ - void removeTipAnimation(); - - /** @brief Adjusts effects after a clip resize. - * @param item The item that was resized - * @param oldInfo pre resize info - * @param fromStart false = resize from end - * @param command Used as a parent for EditEffectCommand */ - void adjustEffects(ClipItem *item, const ItemInfo &oldInfo, QUndoCommand *command); - - /** @brief Prepare an add clip command for an effect */ - void processEffect(ClipItem *item, const QDomElement &effect, int offset, QUndoCommand *effectCommand); - /** @brief Reload all clips and transitions from MLT's playlist */ - void reloadTimeline(); - /** @brief Timeline selection changed, update effect stack. */ - void updateTimelineSelection(); - /** @brief Break groups containing an item in a locked track. */ - void breakLockedGroups(const QList &clipsToMove, const QList &transitionsToMove, QUndoCommand *masterCommand, bool doIt = true); - void slotTrackUp(); - void slotTrackDown(); - -private slots: - void slotRefreshGuides(); - void slotEditTimeLineGuide(); - void slotDeleteTimeLineGuide(); - void checkTrackSequence(int track); - void slotGoToMarker(QAction *action); - /** @brief Context menu is finished, prepare resetting las known menu pos. */ - void slotResetMenuPosition(); - /** @brief Context menu is finished, restore normal operation mode. */ - void slotContextMenuActivated(); - void slotDoResetMenuPosition(); - /** @brief A Filter job producer results. */ - void slotGotFilterJobResults(const QString &id, int startPos, int track, const stringMap &filterParams, const stringMap &extra); - /** @brief Replace a producer in all tracks (for example when proxying a clip). */ - void slotReplaceTimelineProducer(const QString &id); - void slotPrepareTimelineReplacement(const QString &id); - /** @brief Update a producer in all tracks (for example when an effect changed). */ - void slotUpdateTimelineProducer(const QString &id); - void slotEditKeyframeType(QAction *action); - void slotAttachKeyframeToEnd(bool attach); - void disableClip(); - void slotAcceptRipple(bool accept); - void doRipple(bool accept); - -signals: - void cursorMoved(int, int); - void zoomIn(bool zoomOnMouse); - void zoomOut(bool zoomOnMouse); - void mousePosition(int); - /** @brief A clip was selected in timeline, update the effect stack - * @param clip The clip - * @param raise If true, the effect stack widget will be raised (come to front). */ - void clipItemSelected(ClipItem *clip, bool reloadStack = true); - void transitionItemSelected(Transition *, int track = 0, QPoint p = QPoint(), bool update = false); - void activateDocumentMonitor(); - void tracksChanged(); - void displayMessage(const QString &, MessageType); - void doTrackLock(int, bool); - void updateClipMarkers(ClipController *); - void updateTrackHeaders(); - void playMonitor(); - void pauseMonitor(); - /** @brief Monitor document changes (for example the presence of audio data in timeline for export widget.*/ - void documentModified(); - void showTrackEffects(int, TrackInfo); - /** @brief Update the track effect button that shows if a track has effects or not.*/ - void updateTrackEffectState(int); - /** @brief Cursor position changed, repaint ruler.*/ - void updateRuler(int pos); - /** @brief Send data from a clip to be imported as keyframes for effect / transition.*/ - void importKeyframes(GraphicsRectItem type, const QString &, const QString &); - /** @brief Guides were changed, inform render widget*/ - void guidesUpdated(); - /** @brief Prepare importing and expand of a playlist clip */ - void importPlaylistClips(const ItemInfo &info, const QString &url, QUndoCommand *expandCommand); - /** @brief Show a specific frame in clip monitor */ - void showClipFrame(const QString &id, int frame); - /** @brief Select active keyframe in effect stack */ - void setActiveKeyframe(int); - void loadMonitorScene(MonitorSceneType, bool); - void updateTrimMode(const QString &mode = QString()); - void setQmlProperty(const QString &, const QVariant &); -}; - -#endif diff --git a/src/timeline/effectmanager.cpp b/src/timeline/effectmanager.cpp deleted file mode 100644 index 0ddee20b5..000000000 --- a/src/timeline/effectmanager.cpp +++ /dev/null @@ -1,474 +0,0 @@ -/* - * Kdenlive timeline clip handling MLT producer - * Copyright 2015 Kdenlive team - * Author: Vincent Pinon - * - * This program 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) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * This program 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 this program. If not, see . - * - */ - -#include "effectmanager.h" -#include - -EffectManager::EffectManager(Mlt::Service &producer, QObject *parent) - : QObject(parent) - , m_producer(producer) -{ -} - -EffectManager::EffectManager(EffectManager &other) - : QObject() -{ - m_producer = other.producer(); -} - -EffectManager::~EffectManager() = default; - -EffectManager &EffectManager::operator=(EffectManager &other) -{ - m_producer = other.producer(); - return *this; -} - -Mlt::Service &EffectManager::producer() -{ - return m_producer; -} - -void EffectManager::setProducer(Mlt::Service &producer) -{ - m_producer = producer; -} - -/*void Clip::adjustEffectsLength() -{ - int ct = 0; - Mlt::Filter *filter = m_producer.filter(ct); - while (filter) { - if (filter->get_int("kdenlive:sync_in_out") == 1) { - filter->set_in_and_out(m_producer.get_in(), m_producer.get_out()); - } - ct++; - filter = m_producer.filter(ct); - } -}*/ - -bool EffectManager::addEffect(const EffectsParameterList ¶ms, int duration) -{ - bool updateIndex = false; - const int filter_ix = params.paramValue(QStringLiteral("kdenlive_ix")).toInt(); - int ct = 0; - QList filters; - m_producer.lock(); - Mlt::Filter *filter = m_producer.filter(ct); - while (filter != nullptr) { - filters << filter; - if (filter->get_int("kdenlive_ix") == filter_ix) { - // A filter at that position already existed, so we will increase all indexes later - updateIndex = true; - break; - } - ct++; - filter = m_producer.filter(ct); - } - - if (params.paramValue(QStringLiteral("id")) == QLatin1String("speed")) { - // special case, speed effect is not really inserted, we just update the other effects index (kdenlive_ix) - ct = 0; - filter = m_producer.filter(ct); - while (filter != nullptr) { - filters << filter; - if (filter->get_int("kdenlive_ix") >= filter_ix) { - if (updateIndex) { - filter->set("kdenlive_ix", filter->get_int("kdenlive_ix") + 1); - } - } - ct++; - filter = m_producer.filter(ct); - } - m_producer.unlock(); - qDeleteAll(filters); - return true; - } - - // temporarily remove all effects after insert point - QList filtersList; - ct = 0; - filter = m_producer.filter(ct); - while (filter != nullptr) { - if (filter->get_int("kdenlive_ix") >= filter_ix) { - filtersList.append(filter); - m_producer.detach(*filter); - } else { - ct++; - } - filter = m_producer.filter(ct); - } - - // Add new filter - bool success = doAddFilter(params, duration); - // re-add following filters - for (int i = 0; i < filtersList.count(); ++i) { - Mlt::Filter *cur_filter = filtersList.at(i); - if (updateIndex) { - cur_filter->set("kdenlive_ix", cur_filter->get_int("kdenlive_ix") + 1); - } - m_producer.attach(*cur_filter); - } - m_producer.unlock(); - qDeleteAll(filters); - qDeleteAll(filtersList); - return success; -} - -bool EffectManager::doAddFilter(EffectsParameterList params, int duration) -{ - // create filter - QString tag = params.paramValue(QStringLiteral("tag")); - QLocale locale; - ////qCDebug(KDENLIVE_LOG) << " / / INSERTING EFFECT: " << tag << ", REGI: " << region; - QString kfr = params.paramValue(QStringLiteral("keyframes")); - if (!kfr.isEmpty()) { - QStringList keyFrames = kfr.split(QLatin1Char(';'), QString::SkipEmptyParts); - char *starttag = qstrdup(params.paramValue(QStringLiteral("starttag"), QStringLiteral("start")).toUtf8().constData()); - char *endtag = qstrdup(params.paramValue(QStringLiteral("endtag"), QStringLiteral("end")).toUtf8().constData()); - ////qCDebug(KDENLIVE_LOG) << "// ADDING KEYFRAME TAGS: " << starttag << ", " << endtag; - // double max = params.paramValue("max").toDouble(); - double min = params.paramValue(QStringLiteral("min")).toDouble(); - double factor = params.paramValue(QStringLiteral("factor"), QStringLiteral("1")).toDouble(); - double paramOffset = params.paramValue(QStringLiteral("offset"), QStringLiteral("0")).toDouble(); - params.removeParam(QStringLiteral("starttag")); - params.removeParam(QStringLiteral("endtag")); - params.removeParam(QStringLiteral("keyframes")); - params.removeParam(QStringLiteral("min")); - params.removeParam(QStringLiteral("max")); - params.removeParam(QStringLiteral("factor")); - params.removeParam(QStringLiteral("offset")); - // Special case, only one keyframe, means we want a constant value - if (keyFrames.count() == 1) { - Mlt::Filter *filter = new Mlt::Filter(*m_producer.profile(), qstrdup(tag.toUtf8().constData())); - if ((filter != nullptr) && filter->is_valid()) { - filter->set("kdenlive_id", qstrdup(params.paramValue(QStringLiteral("id")).toUtf8().constData())); - int x1 = keyFrames.at(0).section(QLatin1Char('='), 0, 0).toInt(); - double y1 = keyFrames.at(0).section(QLatin1Char('='), 1, 1).toDouble(); - for (int j = 0; j < params.count(); ++j) { - filter->set(params.at(j).name().toUtf8().constData(), params.at(j).value().toUtf8().constData()); - } - filter->set("in", x1); - ////qCDebug(KDENLIVE_LOG) << "// ADDING KEYFRAME vals: " << min<<" / "<set(starttag, locale.toString(((min + y1) - paramOffset) / factor).toUtf8().data()); - m_producer.attach(*filter); - delete filter; - } else { - delete[] starttag; - delete[] endtag; - // qCDebug(KDENLIVE_LOG) << "filter is nullptr"; - m_producer.unlock(); - return false; - } - } else - for (int i = 0; i < keyFrames.size() - 1; ++i) { - Mlt::Filter *filter = new Mlt::Filter(*m_producer.profile(), qstrdup(tag.toUtf8().constData())); - if ((filter != nullptr) && filter->is_valid()) { - filter->set("kdenlive_id", qstrdup(params.paramValue(QStringLiteral("id")).toUtf8().constData())); - int x1 = keyFrames.at(i).section(QLatin1Char('='), 0, 0).toInt(); - double y1 = keyFrames.at(i).section(QLatin1Char('='), 1, 1).toDouble(); - int x2 = keyFrames.at(i + 1).section(QLatin1Char('='), 0, 0).toInt(); - double y2 = keyFrames.at(i + 1).section(QLatin1Char('='), 1, 1).toDouble(); - if (x2 == -1) { - x2 = duration; - } - // non-overlapping sections - if (i > 0) { - y1 += (y2 - y1) / (x2 - x1); - ++x1; - } - - for (int j = 0; j < params.count(); ++j) { - filter->set(params.at(j).name().toUtf8().constData(), params.at(j).value().toUtf8().constData()); - } - - filter->set("in", x1); - filter->set("out", x2); - ////qCDebug(KDENLIVE_LOG) << "// ADDING KEYFRAME vals: " << min<<" / "<set(starttag, locale.toString(((min + y1) - paramOffset) / factor).toUtf8().data()); - filter->set(endtag, locale.toString(((min + y2) - paramOffset) / factor).toUtf8().data()); - m_producer.attach(*filter); - delete filter; - } else { - delete[] starttag; - delete[] endtag; - // qCDebug(KDENLIVE_LOG) << "filter is nullptr"; - m_producer.unlock(); - return false; - } - } - delete[] starttag; - delete[] endtag; - } else { - Mlt::Filter *filter; - QString prefix; - filter = new Mlt::Filter(*m_producer.profile(), qstrdup(tag.toUtf8().constData())); - if ((filter != nullptr) && filter->is_valid()) { - filter->set("kdenlive_id", qstrdup(params.paramValue(QStringLiteral("id")).toUtf8().constData())); - } else { - // qCDebug(KDENLIVE_LOG) << "filter is nullptr"; - m_producer.unlock(); - return false; - } - params.removeParam(QStringLiteral("kdenlive_id")); - if (params.paramValue(QStringLiteral("kdenlive:sync_in_out")) == QLatin1String("1")) { - // This effect must sync in / out with parent clip - // params.removeParam(QStringLiteral("_sync_in_out")); - filter->set_in_and_out(m_producer.get_int("in"), m_producer.get_int("out")); - } - - for (int j = 0; j < params.count(); ++j) { - filter->set((prefix + params.at(j).name()).toUtf8().constData(), params.at(j).value().toUtf8().constData()); - } - - if (tag == QLatin1String("sox")) { - QString effectArgs = params.paramValue(QStringLiteral("id")).section(QLatin1Char('_'), 1); - - params.removeParam(QStringLiteral("id")); - params.removeParam(QStringLiteral("kdenlive_ix")); - params.removeParam(QStringLiteral("tag")); - params.removeParam(QStringLiteral("disable")); - params.removeParam(QStringLiteral("region")); - - for (int j = 0; j < params.count(); ++j) { - effectArgs.append(QLatin1Char(' ') + params.at(j).value()); - } - ////qCDebug(KDENLIVE_LOG) << "SOX EFFECTS: " << effectArgs.simplified(); - filter->set("effect", effectArgs.simplified().toUtf8().constData()); - } - // attach filter to the clip - m_producer.attach(*filter); - delete filter; - } - return true; -} - -bool EffectManager::editEffect(const EffectsParameterList ¶ms, int duration, bool replaceEffect) -{ - int index = params.paramValue(QStringLiteral("kdenlive_ix")).toInt(); - QString tag = params.paramValue(QStringLiteral("tag")); - - if (!params.paramValue(QStringLiteral("keyframes")).isEmpty() || replaceEffect || tag.startsWith(QLatin1String("ladspa")) || tag == QLatin1String("sox") || - tag == QLatin1String("autotrack_rectangle")) { - // This is a keyframe effect, to edit it, we remove it and re-add it. - if (removeEffect(index, false)) { - return addEffect(params, duration); - } - } - - // find filter - int ct = 0; - Mlt::Filter *filter = m_producer.filter(ct); - while (filter != nullptr) { - if (filter->get_int("kdenlive_ix") == index) { - break; - } - delete filter; - ct++; - filter = m_producer.filter(ct); - } - - if (!filter) { - qCDebug(KDENLIVE_LOG) << "WARINIG, FILTER FOR EDITING NOT FOUND, ADDING IT! " << index << ", " << tag; - // filter was not found, it was probably a disabled filter, so add it to the correct place... - - bool success = addEffect(params, duration); - return success; - } - ct = 0; - QString ser = QString::fromLatin1(filter->get("mlt_service")); - QList filtersList; - m_producer.lock(); - if (ser != tag) { - // Effect service changes, delete effect and re-add it - m_producer.detach(*filter); - delete filter; - // Delete all effects after deleted one - filter = m_producer.filter(ct); - while (filter != nullptr) { - if (filter->get_int("kdenlive_ix") > index) { - filtersList.append(filter); - m_producer.detach(*filter); - } else { - ct++; - } - delete filter; - filter = m_producer.filter(ct); - } - - // re-add filter - doAddFilter(params, duration); - m_producer.unlock(); - return true; - } - if (params.hasParam(QStringLiteral("kdenlive:sync_in_out"))) { - if (params.paramValue(QStringLiteral("kdenlive:sync_in_out")) == QLatin1String("1")) { - // This effect must sync in / out with parent clip - // params.removeParam(QStringLiteral("sync_in_out")); - filter->set_in_and_out(m_producer.get_int("in"), m_producer.get_int("out")); - } else { - // Reset in/out properties - filter->set("in", (char *)nullptr); - filter->set("out", (char *)nullptr); - } - } - - for (int j = 0; j < params.count(); ++j) { - filter->set(params.at(j).name().toUtf8().constData(), params.at(j).value().toUtf8().constData()); - } - - for (int j = 0; j < filtersList.count(); ++j) { - m_producer.attach(*(filtersList.at(j))); - } - qDeleteAll(filtersList); - m_producer.unlock(); - delete filter; - return true; -} - -bool EffectManager::removeEffect(int effectIndex, bool updateIndex) -{ - m_producer.lock(); - int ct = 0; - bool success = false; - Mlt::Filter *filter = m_producer.filter(ct); - QList filters; - while (filter != nullptr) { - filters << filter; - if ((effectIndex == -1 && (strcmp(filter->get("kdenlive_id"), "") != 0)) || filter->get_int("kdenlive_ix") == effectIndex) { - if (m_producer.detach(*filter) == 0) { - success = true; - } - } else if (updateIndex) { - // Adjust the other effects index - if (filter->get_int("kdenlive_ix") > effectIndex) { - filter->set("kdenlive_ix", filter->get_int("kdenlive_ix") - 1); - } - ct++; - } else { - ct++; - } - filter = m_producer.filter(ct); - } - m_producer.unlock(); - qDeleteAll(filters); - return success; -} - -bool EffectManager::enableEffects(const QList &effectIndexes, bool disable, bool rememberState) -{ - int ct = 0; - bool success = false; - Mlt::Filter *filter = m_producer.filter(ct); - while (filter != nullptr) { - if (effectIndexes.isEmpty() || effectIndexes.contains(filter->get_int("kdenlive_ix"))) { - // m_producer.lock(); - if (rememberState) { - if (disable && filter->get_int("disable") == 0) { - filter->set("auto_disable", 1); - filter->set("disable", (int)disable); - } else if (!disable && filter->get_int("auto_disable") == 1) { - filter->set("disable", (char *)nullptr); - filter->set("auto_disable", (char *)nullptr); - } - } else { - filter->set("disable", (int)disable); - } - success = true; - // m_producer.unlock(); - } - delete filter; - ct++; - filter = m_producer.filter(ct); - } - return success; -} - -bool EffectManager::moveEffect(int oldPos, int newPos) -{ - int ct = 0; - QList filtersList; - QList toDelete; - Mlt::Filter *filter = m_producer.filter(ct); - if (newPos > oldPos) { - bool found = false; - while (filter != nullptr) { - toDelete << filter; - if (!found && filter->get_int("kdenlive_ix") == oldPos) { - filter->set("kdenlive_ix", newPos); - filtersList.append(filter); - m_producer.detach(*filter); - filter = m_producer.filter(ct); - while ((filter != nullptr) && filter->get_int("kdenlive_ix") <= newPos) { - filter->set("kdenlive_ix", filter->get_int("kdenlive_ix") - 1); - ct++; - filter = m_producer.filter(ct); - } - found = true; - } - if ((filter != nullptr) && filter->get_int("kdenlive_ix") > newPos) { - filtersList.append(filter); - m_producer.detach(*filter); - } else { - ct++; - } - filter = m_producer.filter(ct); - } - } else { - while (filter != nullptr) { - toDelete << filter; - if (filter->get_int("kdenlive_ix") == oldPos) { - filter->set("kdenlive_ix", newPos); - filtersList.append(filter); - m_producer.detach(*filter); - } else { - ct++; - } - filter = m_producer.filter(ct); - } - - ct = 0; - filter = m_producer.filter(ct); - while (filter != nullptr) { - toDelete << filter; - int pos = filter->get_int("kdenlive_ix"); - if (pos >= newPos) { - if (pos < oldPos) { - filter->set("kdenlive_ix", pos + 1); - } - filtersList.append(filter); - m_producer.detach(*filter); - } else { - ct++; - } - filter = m_producer.filter(ct); - } - } - - for (int i = 0; i < filtersList.count(); ++i) { - m_producer.attach(*(filtersList.at(i))); - } - qDeleteAll(toDelete); - // TODO: check for success - return true; -} diff --git a/src/timeline/effectmanager.h b/src/timeline/effectmanager.h deleted file mode 100644 index b2005a47b..000000000 --- a/src/timeline/effectmanager.h +++ /dev/null @@ -1,58 +0,0 @@ -/* - * Kdenlive timeline clip handling MLT producer - * Copyright 2016 Kdenlive team - * Author: Jean-Baptiste Mardelle - * - * This program 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) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * This program 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 this program. If not, see . - * - */ - -#ifndef EFFECTMANAGER_H -#define EFFECTMANAGER_H - -#include -#include -#include - -#include "mltcontroller/effectscontroller.h" - -class EffectManager : public QObject -{ - Q_OBJECT - Q_PROPERTY(Mlt::Producer producer READ producer WRITE setProducer) - -public: - explicit EffectManager(Mlt::Service &producer, QObject *parent = nullptr); - EffectManager(EffectManager &other); - ~EffectManager(); - EffectManager &operator=(EffectManager &other); - Mlt::Service &producer(); - void setProducer(Mlt::Service &producer); - bool addEffect(const EffectsParameterList ¶ms, int duration); - bool doAddFilter(EffectsParameterList params, int duration); - bool editEffect(const EffectsParameterList ¶ms, int duration, bool replaceEffect); - bool removeEffect(int effectIndex, bool updateIndex); - bool enableEffects(const QList &effectIndexes, bool disable, bool rememberState = false); - bool moveEffect(int oldPos, int newPos); - -public Q_SLOTS: - -private: - Mlt::Service m_producer; -}; - -#endif // CLIP_H diff --git a/src/timeline/guide.cpp b/src/timeline/guide.cpp deleted file mode 100644 index 6b176b93c..000000000 --- a/src/timeline/guide.cpp +++ /dev/null @@ -1,175 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "guide.h" -#include "customtrackview.h" - -#include "kdenlivesettings.h" - -#include -#include -#include -#include -#include -#include - -Guide::Guide(CustomTrackView *view, const GenTime &pos, const QString &label, double height) - : QGraphicsLineItem() - , m_position(pos) - , m_label(label) - , m_view(view) - , m_pen(QPen()) -{ - setFlags(QGraphicsItem::ItemIsMovable | QGraphicsItem::ItemIgnoresTransformations); - setFlag(QGraphicsItem::ItemSendsGeometryChanges, true); - setToolTip(label); - setLine(0, 0, 0, height); - if (m_position < GenTime()) { - m_position = GenTime(); - } - setPos(m_position.frames(m_view->fps()), 0); - m_pen.setWidthF(0); - m_pen.setColor(QColor(0, 0, 200, 180)); - // m_pen.setCosmetic(true); - setPen(m_pen); - setZValue(999); - setAcceptHoverEvents(true); - const QFontMetrics metric = m_view->fontMetrics(); - m_width = metric.width(QLatin1Char(' ') + m_label + QLatin1Char(' ')) + 2; - prepareGeometryChange(); -} - -QString Guide::label() const -{ - return m_label; -} - -GenTime Guide::position() const -{ - return m_position; -} - -CommentedTime Guide::info() const -{ - return CommentedTime(m_position, m_label); -} - -void Guide::updateGuide(const GenTime &newPos, const QString &comment) -{ - m_position = newPos; - setPos(m_position.frames(m_view->fps()), 0); - if (!comment.isEmpty()) { - m_label = comment; - setToolTip(m_label); - const QFontMetrics metric = m_view->fontMetrics(); - m_width = metric.width(QLatin1Char(' ') + m_label + QLatin1Char(' ')) + 2; - prepareGeometryChange(); - } -} - -void Guide::updatePos() -{ - setPos(m_position.frames(m_view->fps()), 0); -} - -// virtual -int Guide::type() const -{ - return GUIDEITEM; -} - -// virtual -void Guide::hoverEnterEvent(QGraphicsSceneHoverEvent *) -{ - m_pen.setColor(QColor(200, 0, 0, 180)); - setPen(m_pen); -} - -// virtual -void Guide::hoverLeaveEvent(QGraphicsSceneHoverEvent *) -{ - m_pen.setColor(QColor(0, 0, 200, 180)); - setPen(m_pen); -} - -// virtual -QVariant Guide::itemChange(GraphicsItemChange change, const QVariant &value) -{ - if (change == ItemPositionChange && (scene() != nullptr)) { - // value is the new position. - QPointF newPos = value.toPointF(); - newPos.setY(0); - newPos.setX(m_view->getSnapPointForPos(newPos.x())); - if (newPos.x() < 0.0) { - newPos.setX(0.0); - } - return newPos; - } - return QGraphicsItem::itemChange(change, value); -} - -// virtual -QRectF Guide::boundingRect() const -{ - double scale = m_view->matrix().m11(); - double width = m_pen.widthF() / scale * 2; - QRectF rect(line().x1() - width / 2, line().y1(), width, line().y2() - line().y1()); - if (KdenliveSettings::showmarkers()) { - // +3 to cover the arc at the end of the comment - rect.setWidth(width + m_width + 3); - } - return rect; -} - -// virtual -QPainterPath Guide::shape() const -{ - QPainterPath path; - if (!scene()) { - return path; - } - double width = m_pen.widthF() * 2; - path.addRect(line().x1() - width / 2, line().y1(), width, line().y2() - line().y1()); - if (KdenliveSettings::showmarkers() && (scene()->views().count() != 0)) { - const QFontMetrics metric = m_view->fontMetrics(); - int offset = scene()->views()[0]->verticalScrollBar()->value(); - QRectF txtBounding(line().x1(), line().y1() + offset, m_width, metric.height()); - path.addRect(txtBounding); - } - return path; -} - -// virtual -void Guide::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * /*w*/) -{ - QGraphicsLineItem::paint(painter, option); - if (KdenliveSettings::showmarkers() && (scene() != nullptr) && (scene()->views().count() != 0)) { - QPointF p1 = line().p1(); - const QFontMetrics metric = m_view->fontMetrics(); - painter->setClipRect(option->rect); - // makes sure the text stays visible when scrolling vertical - int offset = scene()->views()[0]->verticalScrollBar()->value(); - - QRectF txtBounding = painter->boundingRect(p1.x(), p1.y() + offset, m_width, metric.height(), Qt::AlignLeft | Qt::AlignTop, m_label); - painter->setBrush(QBrush(m_pen.color())); - painter->drawRoundedRect(txtBounding.adjusted(-5, -5, 2, 1), 3, 3); - painter->setPen(Qt::white); - painter->drawText(txtBounding.adjusted(1, 0, 1, 0), Qt::AlignCenter, m_label); - } -} diff --git a/src/timeline/guide.h b/src/timeline/guide.h deleted file mode 100644 index d92e2c5ca..000000000 --- a/src/timeline/guide.h +++ /dev/null @@ -1,61 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef GUIDE_H -#define GUIDE_H - -#include -#include - -#include "definitions.h" -#include "gentime.h" - -#define GUIDEITEM 8000 - -class CustomTrackView; - -class Guide : public QGraphicsLineItem -{ - -public: - Guide(CustomTrackView *view, const GenTime &pos, const QString &label, double height); - GenTime position() const; - void updateGuide(const GenTime &newPos, const QString &comment = QString()); - QString label() const; - CommentedTime info() const; - void updatePos(); - int type() const override; - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *w) override; - QRectF boundingRect() const override; - QPainterPath shape() const override; - -protected: - void hoverEnterEvent(QGraphicsSceneHoverEvent *) override; - void hoverLeaveEvent(QGraphicsSceneHoverEvent *) override; - QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; - -private: - GenTime m_position; - QString m_label; - CustomTrackView *m_view; - int m_width; - QPen m_pen; -}; - -#endif diff --git a/src/timeline/headertrack.cpp b/src/timeline/headertrack.cpp deleted file mode 100644 index 8cd89d405..000000000 --- a/src/timeline/headertrack.cpp +++ /dev/null @@ -1,352 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "headertrack.h" -#include "effectslist/effectslist.h" -#include "kdenlivesettings.h" -#include "track.h" -#include "utils/KoIconUtils.h" - -#include -#include -#include - -#include "kdenlive_debug.h" -#include -#include -#include -#include -#include -#include - -HeaderTrack::HeaderTrack(const TrackInfo &info, const QList &actions, Track *parent, int height, QWidget *parentWidget) - : QWidget(parentWidget) - , isTarget(false) - , m_type(info.type) - , m_parentTrack(parent) - , m_isSelected(false) - , m_switchVideo(nullptr) -{ - setupUi(this); - setFocusPolicy(Qt::ClickFocus); - m_name = info.trackName.isEmpty() ? QString::number(m_parentTrack->index()) : info.trackName; - m_tb = new QToolBar(this); - m_tb->setToolButtonStyle(Qt::ToolButtonIconOnly); - setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); - m_tb->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Preferred); - m_tb->setContentsMargins(0, 0, 0, 0); - int iconSize = m_tb->iconSize().width(); - QSize s(iconSize, iconSize); - track_number->setText(m_name); - track_number->setContextMenuPolicy(Qt::NoContextMenu); - track_number->installEventFilter(this); - track_number->setEnabled(false); - connect(track_number, &QLineEdit::editingFinished, this, &HeaderTrack::slotRenameTrack); - effect_label->setPixmap(KoIconUtils::themedIcon(QStringLiteral("kdenlive-track_has_effect")).pixmap(s)); - updateEffectLabel(info.effectsList.effectNames()); - setAcceptDrops(true); - - QFontMetrics metrics(font()); - int trackHeight = metrics.height() + qApp->style()->pixelMetric(QStyle::PM_ToolBarIconSize); - if (height < trackHeight) { - horizontalLayout->addWidget(m_tb); - } else { - button_layout->addWidget(m_tb); - } - m_switchLock = new KDualAction(i18n("Lock track"), i18n("Unlock track"), this); - m_switchLock->setActiveIcon(KoIconUtils::themedIcon(QStringLiteral("kdenlive-lock"))); - m_switchLock->setInactiveIcon(KoIconUtils::themedIcon(QStringLiteral("kdenlive-unlock"))); - m_switchLock->setActive(info.isLocked); - connect(m_switchLock, &KDualAction::activeChanged, this, &HeaderTrack::switchLock); - m_tb->addAction(m_switchLock); - m_switchAudio = new KDualAction(i18n("Disable audio"), i18n("Enable audio"), this); - m_switchAudio->setActiveIcon(KoIconUtils::themedIcon(QStringLiteral("kdenlive-hide-audio"))); - m_switchAudio->setInactiveIcon(KoIconUtils::themedIcon(QStringLiteral("kdenlive-show-audio"))); - m_switchAudio->setActive(info.isMute); - connect(m_switchAudio, &KDualAction::activeChanged, this, &HeaderTrack::switchAudio); - m_tb->addAction(m_switchAudio); - setAutoFillBackground(true); - if (m_type == VideoTrack) { - m_switchVideo = new KDualAction(i18n("Disable video"), i18n("Enable video"), this); - m_switchVideo->setActiveIcon(KoIconUtils::themedIcon(QStringLiteral("kdenlive-hide-video"))); - m_switchVideo->setInactiveIcon(KoIconUtils::themedIcon(QStringLiteral("kdenlive-show-video"))); - m_switchVideo->setActive(info.isBlind); - connect(m_switchVideo, &KDualAction::activeChanged, this, &HeaderTrack::switchVideo); - m_tb->addAction(m_switchVideo); - } else { - setBackgroundRole(QPalette::AlternateBase); - m_switchVideo = nullptr; - } - - updateStatus(info); - setFixedHeight(height); - setMinimumWidth(m_tb->widgetForAction(m_switchLock)->width() * 1.5); - setContextMenuPolicy(Qt::ActionsContextMenu); - addActions(actions); -} - -HeaderTrack::~HeaderTrack() -{ - // qCDebug(KDENLIVE_LOG)<<" - --DEL TK HEAD: "<type() == QEvent::MouseButtonPress) { - // Make sure to select current track when clicking in track name widget - emit selectTrack(m_parentTrack->index()); - } else if (event->type() == QEvent::MouseButtonDblClick) { - // Allow editing on double click - track_number->setEnabled(true); - track_number->setFocus(Qt::MouseFocusReason); - event->accept(); - } - return QWidget::eventFilter(obj, event); -} - -void HeaderTrack::updateStatus(const TrackInfo &info) -{ - m_switchAudio->setActive(info.isMute); - if (m_switchVideo) { - m_switchVideo->setActive(info.isBlind); - } - m_switchLock->setActive(info.isLocked); - updateBackground(info.isLocked); - updateLed(); - renameTrack(info.trackName); -} - -void HeaderTrack::updateBackground(bool isLocked) -{ - if (isLocked) { - setBackgroundRole(m_isSelected ? QPalette::Dark : QPalette::Shadow); - } else if (m_isSelected) { - setBackgroundRole(QPalette::Mid); - } else if (m_type == VideoTrack) { - setBackgroundRole(QPalette::Base); - } else { - setBackgroundRole(QPalette::AlternateBase); - } -} - -void HeaderTrack::updateEffectLabel(const QStringList &effects) -{ - if (!effects.isEmpty()) { - effect_label->setHidden(false); - effect_label->setToolTip(effects.join(QLatin1Char('/'))); - } else { - effect_label->setHidden(true); - effect_label->setToolTip(QString()); - } -} - -// virtual -void HeaderTrack::mousePressEvent(QMouseEvent *event) -{ - if (track_number->hasFocus()) { - track_number->clearFocus(); - } - // Necessary in case another track name has focus - setFocus(); - QWidget *underMouse = childAt(event->pos()); - emit selectTrack(m_parentTrack->index(), underMouse == kled); - event->setAccepted(true); -} - -void HeaderTrack::mouseDoubleClickEvent(QMouseEvent *event) -{ - if (track_number->hasFocus()) { - track_number->clearFocus(); - } - emit configTrack(); - event->setAccepted(true); - QWidget::mouseDoubleClickEvent(event); -} - -// virtual -void HeaderTrack::dropEvent(QDropEvent *event) -{ - const QString effects = QString::fromUtf8(event->mimeData()->data(QStringLiteral("kdenlive/effectslist"))); - QDomDocument doc; - doc.setContent(effects, true); - QDomElement e = doc.documentElement(); - if (e.tagName() == QLatin1String("effectgroup")) { - // dropped an effect group - QDomNodeList effectlist = e.elementsByTagName(QStringLiteral("effect")); - for (int i = 0; i < effectlist.count(); ++i) { - effectlist.at(i).toElement().removeAttribute(QStringLiteral("kdenlive_ix")); - } - } else { - // single effect dropped - e.removeAttribute(QStringLiteral("kdenlive_ix")); - } - emit selectTrack(m_parentTrack->index()); - emit addTrackEffect(e, m_parentTrack->index()); -} - -// virtual -void HeaderTrack::dragEnterEvent(QDragEnterEvent *event) -{ - if (m_switchLock->isActive()) { - event->setAccepted(false); - } else { - if (event->mimeData()->hasFormat(QStringLiteral("kdenlive/effectslist"))) { - const QString effects = QString::fromUtf8(event->mimeData()->data(QStringLiteral("kdenlive/effectslist"))); - QDomDocument doc; - doc.setContent(effects, true); - if (doc.documentElement().attribute(QStringLiteral("id")) != QLatin1String("speed")) { - event->setAccepted(true); - } - } - } -} - -void HeaderTrack::setSelectedIndex(int ix) -{ - m_isSelected = ix == m_parentTrack->index(); - updateBackground(m_switchLock->isActive()); - updateLed(); -} - -void HeaderTrack::adjustSize(int height) -{ - // Don't show track buttons if size is too small - QFontMetrics metrics(font()); - int trackHeight = metrics.height(); - QStyle *style = qApp->style(); - trackHeight += style->pixelMetric(QStyle::PM_ToolBarIconSize); - bool smallTracks = height < trackHeight; - if (smallTracks) { - int ix = button_layout->indexOf(m_tb); - if (ix != -1) { - // Move toolbar to the right of track label - QLayoutItem *item = button_layout->takeAt(ix); - delete item; - horizontalLayout->addWidget(m_tb); - } - } else { - int ix = horizontalLayout->indexOf(m_tb); - if (ix != -1) { - QLayoutItem *item = horizontalLayout->takeAt(ix); - delete item; - button_layout->addWidget(m_tb); - } - } - // m_tb->setHidden(smallTracks); - setFixedHeight(height); -} - -void HeaderTrack::switchVideo(bool enable) -{ - emit switchTrackVideo(m_parentTrack->index(), enable); - updateLed(); -} - -void HeaderTrack::switchAudio(bool enable) -{ - emit switchTrackAudio(m_parentTrack->index(), enable); - updateLed(); -} - -void HeaderTrack::switchLock(bool enable) -{ - emit switchTrackLock(m_parentTrack->index(), enable); -} - -void HeaderTrack::setVideoMute(bool mute) -{ - m_switchVideo->blockSignals(true); - m_switchVideo->setActive(mute); - m_switchVideo->blockSignals(false); - updateLed(); -} - -void HeaderTrack::setAudioMute(bool mute) -{ - m_switchAudio->blockSignals(true); - m_switchAudio->setActive(mute); - m_switchAudio->blockSignals(false); - updateLed(); -} - -void HeaderTrack::setLock(bool lock) -{ - m_switchLock->blockSignals(true); - m_switchLock->setActive(lock); - m_switchLock->blockSignals(false); - updateBackground(lock); - updateLed(); -} - -void HeaderTrack::switchTarget(bool enable) -{ - isTarget = enable; - updateLed(); -} - -void HeaderTrack::updateLed() -{ - if (m_switchLock->isActive()) { - // Locked track - kled->setColor(Qt::darkRed); - kled->setToolTip(i18n("Locked track")); - } else if (isTarget && KdenliveSettings::splitaudio()) { - kled->setColor(Qt::darkGreen); - kled->setToolTip(i18n("Target track")); - } else if (m_switchAudio->isActive() || ((m_switchVideo != nullptr) && m_switchVideo->isActive())) { - kled->setColor(0xffcc00); - kled->setToolTip(m_switchAudio->isActive() ? i18n("Muted track") : i18n("Blind track")); - } else { - kled->setToolTip(QString()); - kled->setColor(palette().base().color()); - } -} - -void HeaderTrack::slotRenameTrack() -{ - track_number->clearFocus(); - if (m_name != track_number->text()) { - emit renameTrack(m_parentTrack->index(), track_number->text()); - } - track_number->setEnabled(false); -} - -void HeaderTrack::renameTrack(const QString &name) -{ - m_name = name; - track_number->setText(name); -} - -QString HeaderTrack::name() const -{ - return m_name; -} - -void HeaderTrack::refreshPalette() -{ - QPalette pal = palette(); - KColorScheme scheme(pal.currentColorGroup(), KColorScheme::Window, KSharedConfig::openConfig(KdenliveSettings::colortheme())); - pal.setColor(QPalette::Base, scheme.background(KColorScheme::NormalBackground).color()); - pal.setColor(QPalette::AlternateBase, scheme.background(KColorScheme::AlternateBackground).color()); - pal.setColor(QPalette::Mid, scheme.background(KColorScheme::ActiveBackground).color()); - pal.setColor(QPalette::Shadow, scheme.background(KColorScheme::NeutralBackground).color()); - pal.setColor(QPalette::Dark, scheme.background(KColorScheme::NegativeBackground).color()); - setPalette(pal); - updateLed(); -} diff --git a/src/timeline/headertrack.h b/src/timeline/headertrack.h deleted file mode 100644 index 3c097712b..000000000 --- a/src/timeline/headertrack.h +++ /dev/null @@ -1,89 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef HEADERTRACK_H -#define HEADERTRACK_H - -#include - -#include "definitions.h" -#include "ui_trackheader_ui.h" - -class KDualAction; -class QToolBar; -class Track; - -class HeaderTrack : public QWidget, public Ui::TrackHeader_UI -{ - Q_OBJECT - -public: - HeaderTrack(const TrackInfo &info, const QList &actions, Track *parent, int height, QWidget *parentWidget); - virtual ~HeaderTrack(); - bool isTarget; - void setLock(bool lock); - void adjustSize(int height); - void setSelectedIndex(int ix); - /** @brief Update the track label to show if current track has effects or not.*/ - void updateEffectLabel(const QStringList &effects); - void renameTrack(const QString &name); - QString name() const; - /** @brief Update status of mute/blind/lock/composite buttons.*/ - void updateStatus(const TrackInfo &info); - void refreshPalette(); - void switchTarget(bool enable); - void updateLed(); - void setVideoMute(bool mute); - void setAudioMute(bool mute); - -protected: - void mousePressEvent(QMouseEvent *event) override; - void mouseDoubleClickEvent(QMouseEvent *event) override; - void dropEvent(QDropEvent *event) override; - void dragEnterEvent(QDragEnterEvent *event) override; - bool eventFilter(QObject *obj, QEvent *event) override; - -private: - TrackType m_type; - Track *m_parentTrack; - bool m_isSelected; - QString m_name; - QToolBar *m_tb; - KDualAction *m_switchVideo; - KDualAction *m_switchAudio; - KDualAction *m_switchLock; - void updateBackground(bool isLocked); - -private slots: - void switchAudio(bool); - void switchVideo(bool); - void slotRenameTrack(); - void switchLock(bool); - -signals: - void switchTrackAudio(int index, bool); - void switchTrackVideo(int index, bool); - void switchTrackLock(int index, bool); - void renameTrack(int index, const QString &name); - void selectTrack(int index, bool switchTarget = false); - void configTrack(); - void addTrackEffect(const QDomElement &, int index); -}; - -#endif diff --git a/src/timeline/keyframeview.cpp b/src/timeline/keyframeview.cpp deleted file mode 100644 index 622d6c243..000000000 --- a/src/timeline/keyframeview.cpp +++ /dev/null @@ -1,1120 +0,0 @@ -/* -Copyright (C) 2016 Jean-Baptiste Mardelle -Copyright (C) 2016 Vincent Pinon -This file is part of Kdenlive. See www.kdenlive.org. - -This program 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) version 3 or any later version -accepted by the membership of KDE e.V. (or its successor approved -by the membership of KDE e.V.), which shall act as a proxy -defined in Section 14 of version 3 of the license. - -This program 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 this program. If not, see . -*/ - -#include "klocalizedstring.h" -#include -#include - -#include "keyframeview.h" -#include "mltcontroller/effectscontroller.h" -#include "core.h" -#include "profiles/profilemodel.hpp" - -KeyframeView::KeyframeView(int handleSize, QObject *parent) - : QObject(parent) - , activeKeyframe(-1) - , originalKeyframe(-1) - , attachToEnd(-2) - , duration(0) - , m_keyframeType(KEYFRAMETYPE::NoKeyframe) - , m_keyframeDefault(0) - , m_keyframeMin(0) - , m_keyframeMax(1) - , m_keyframeFactor(1) - , m_handleSize(handleSize) - , m_useOffset(false) - , m_offset(0) -{ -} - -KeyframeView::~KeyframeView() = default; - -double KeyframeView::keyframeUnmap(const QRectF &br, double y) -{ - return ((br.bottom() - y) / br.height() * (m_keyframeMax - m_keyframeMin) + m_keyframeMin) / m_keyframeFactor; -} - -double KeyframeView::keyframeMap(const QRectF &br, double value) -{ - return br.bottom() - br.height() * (value * m_keyframeFactor - m_keyframeMin) / (m_keyframeMax - m_keyframeMin); -} - -QPointF KeyframeView::keyframeMap(const QRectF &br, int frame, double value) -{ - return QPointF(br.x() + br.width() * frame / duration, - br.bottom() - br.height() * (value * m_keyframeFactor - m_keyframeMin) / (m_keyframeMax - m_keyframeMin)); -} - -QPointF KeyframeView::keyframePoint(const QRectF &br, int index) -{ - int frame = m_keyAnim.key_get_frame(index); - return keyframeMap(br, frame < 0 ? frame + duration + m_offset : frame + m_offset, - m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), frame, duration - m_offset)); -} - -QPointF KeyframeView::keyframePoint(const QRectF &br, int frame, double value, double factor, double min, double max) -{ - return QPointF(br.x() + br.width() * frame / duration, br.bottom() - br.height() * (value * factor - min) / (max - min)); -} - -void KeyframeView::drawKeyFrames(const QRectF &br, int length, bool active, QPainter *painter, const QTransform &transformation) -{ - if (duration == 0 || m_inTimeline.isEmpty() || m_keyframeType == NoKeyframe || !m_keyAnim.is_valid() || m_keyAnim.key_count() < 1) { - return; - } - duration = length; - // m_keyAnim.set_length(length); - painter->save(); - QPointF h(m_handleSize, m_handleSize); - - // draw keyframes - // Special case: Geometry keyframes are just vertical lines - if (m_keyframeType == GeometryKeyframe) { - for (int i = 0; i < m_keyAnim.key_count(); ++i) { - int frame = m_keyAnim.key_get_frame(i); - QColor color = (frame == activeKeyframe) ? QColor(Qt::red) : QColor(Qt::blue); - if (active) { - painter->setPen(color); - } - QPointF k = keyframePoint(br, i); - painter->drawLine(transformation.map(QLineF(k.x(), br.top(), k.x(), br.height()))); - if (active) { - k.setY(br.top() + br.height() / 2); - painter->setBrush((m_keyAnim.key_get_frame(i) == activeKeyframe) ? QColor(Qt::red) : QColor(Qt::blue)); - painter->drawEllipse(QRectF(transformation.map(k) - h / 2, transformation.map(k) + h / 2)); - } - } - painter->restore(); - return; - } - - // draw line showing default value - if (active) { - QColor col(Qt::black); - col.setAlpha(140); - painter->fillRect(QRectF(transformation.map(br.topLeft()), transformation.map(br.bottomRight())), col); - double y = keyframeMap(br, m_keyframeDefault); - QLineF line = transformation.map(QLineF(br.x(), y, br.right(), y)); - painter->setPen(QColor(168, 168, 168, 180)); - painter->drawLine(line); - painter->setPen(QColor(108, 108, 108, 180)); - painter->drawLine(line.translated(0, 1)); - painter->setPen(QColor(Qt::white)); - painter->setRenderHint(QPainter::Antialiasing); - // Draw zone where keyframes are attached to end - if (attachToEnd > -2) { - QRectF negZone = br; - negZone.setLeft(br.x() + br.width() * attachToEnd / (double)duration); - QColor neg(Qt::darkYellow); - neg.setAlpha(190); - painter->fillRect(QRectF(transformation.map(negZone.topLeft()), transformation.map(negZone.bottomRight())), neg); - } - } - - int cnt = m_keyProperties.count(); - QStringList paramNames; - paramNames.reserve(cnt); - for (int i = 0; i < cnt; i++) { - paramNames << m_keyProperties.get_name(i); - } - paramNames.removeAll(m_inTimeline); - // Make sure edited param is painted last - paramNames.append(m_inTimeline); - for (const QString ¶mName : paramNames) { - if (m_notInTimeline.contains(paramName)) { - continue; - } - ParameterInfo info = m_paramInfos.value(paramName); - if (info.max == info.min) { - // this is probably an animated rect - continue; - } - Mlt::Animation drawAnim = m_keyProperties.get_animation(paramName.toUtf8().constData()); - if (!drawAnim.is_valid()) { - continue; - } - QPainterPath path; - // Find first key before our clip start, get frame for rect left first - int firstKF = qMax(0, drawAnim.previous_key(-m_offset)); - int lastKF = drawAnim.next_key(duration - m_offset); - if (lastKF < duration - m_offset) { - lastKF = duration - m_offset; - } - int frame = firstKF; - double value = m_keyProperties.anim_get_double(paramName.toUtf8().constData(), frame, duration - m_offset); - QPointF start = keyframePoint(br, frame + m_offset, value, info.factor, info.min, info.max); - path.moveTo(br.x(), br.bottom()); - path.lineTo(br.x(), start.y()); - path.lineTo(start); - painter->setPen(paramName == m_inTimeline ? QColor(Qt::white) : Qt::NoPen); - for (int i = 0; i < drawAnim.key_count(); ++i) { - int currentFrame = drawAnim.key_get_frame(i); - if (currentFrame < firstKF) { - continue; - } - if (currentFrame > lastKF) { - break; - } - if (active && paramName == m_inTimeline) { - painter->setBrush((drawAnim.key_get_frame(i) == activeKeyframe) ? QColor(Qt::red) : QColor(Qt::blue)); - painter->drawEllipse(QRectF(transformation.map(start) - h / 2, transformation.map(start) + h / 2)); - } - if (i + 1 < drawAnim.key_count()) { - frame = drawAnim.key_get_frame(i + 1); - value = m_keyProperties.anim_get_double(paramName.toUtf8().constData(), frame, duration - m_offset); - QPointF end = keyframePoint(br, frame + m_offset, value, info.factor, info.min, info.max); - // QPointF end = keyframePoint(br, i + 1); - switch (drawAnim.key_get_type(i)) { - case mlt_keyframe_discrete: - path.lineTo(end.x(), start.y()); - path.lineTo(end); - break; - case mlt_keyframe_linear: - path.lineTo(end); - break; - case mlt_keyframe_smooth: - frame = drawAnim.key_get_frame(qMax(i - 1, 0)); - value = m_keyProperties.anim_get_double(paramName.toUtf8().constData(), frame, duration - m_offset); - QPointF pre = keyframePoint(br, frame + m_offset, value, info.factor, info.min, info.max); - frame = drawAnim.key_get_frame(qMin(i + 2, drawAnim.key_count() - 1)); - value = m_keyProperties.anim_get_double(paramName.toUtf8().constData(), frame, duration - m_offset); - QPointF post = keyframePoint(br, frame + m_offset, value, info.factor, info.min, info.max); - QPointF c1 = (end - pre) / 6.0; // + start - QPointF c2 = (start - post) / 6.0; // + end - double mid = (end.x() - start.x()) / 2; - if (c1.x() > mid) { - c1 = c1 * mid / c1.x(); // scale down tangent vector to not go beyond middle - } - if (c2.x() < -mid) { - c2 = c2 * -mid / c2.x(); - } - path.cubicTo(start + c1, end + c2, end); - break; - } - start = end; - } else { - path.lineTo(br.right(), start.y()); - } - } - path.lineTo(br.right(), br.bottom()); - if (paramName == m_inTimeline) { - QColor col(Qt::white); - col.setAlpha(active ? 120 : 80); - painter->setBrush(col); - } else { - QColor col; - switch (paramNames.indexOf(paramName)) { - case 0: - col = Qt::blue; - break; - case 1: - col = Qt::green; - break; - case 2: - col = Qt::yellow; - break; - case 3: - col = Qt::red; - break; - case 4: - col = Qt::magenta; - break; - default: - col = Qt::cyan; - break; - } - col.setAlpha(80); - painter->setBrush(col); - } - painter->drawPath(transformation.map(path)); - } - painter->restore(); -} - -void KeyframeView::drawKeyFrameChannels(const QRectF &br, int in, int out, QPainter *painter, const QList &maximas, int limitKeyframes, - const QColor &textColor) -{ - double frameFactor = (double)(out - in) / br.width(); - int offset = 1; - if (limitKeyframes > 0) { - offset = (out - in) / limitKeyframes / frameFactor; - } - double xDist = maximas.at(0).y() - maximas.at(0).x(); - double yDist = maximas.at(1).y() - maximas.at(1).x(); - double wDist = maximas.at(2).y() - maximas.at(2).x(); - double hDist = maximas.at(3).y() - maximas.at(3).x(); - double xOffset = maximas.at(0).x(); - double yOffset = maximas.at(1).x(); - double wOffset = maximas.at(2).x(); - double hOffset = maximas.at(3).x(); - QColor cX(255, 0, 0, 100); - QColor cY(0, 255, 0, 100); - QColor cW(0, 0, 255, 100); - QColor cH(255, 255, 0, 100); - // Draw curves labels - QRectF txtRect = painter->boundingRect(br, QStringLiteral("t")); - txtRect.setX(2); - txtRect.setWidth(br.width() - 4); - txtRect.moveTop(br.height() - txtRect.height()); - QRectF drawnText; - int maxHeight = br.height() - txtRect.height() - 2; - painter->setPen(textColor); - int rectSize = txtRect.height() / 2; - if (xDist > 0) { - painter->fillRect(txtRect.x(), txtRect.top() + rectSize / 2, rectSize, rectSize, cX); - txtRect.setX(txtRect.x() + rectSize * 2); - painter->drawText(txtRect, 0, i18nc("X as in x coordinate", "X") + QStringLiteral(" (%1-%2)").arg(maximas.at(0).x()).arg(maximas.at(0).y()), - &drawnText); - } - if (yDist > 0) { - if (drawnText.isValid()) { - txtRect.setX(drawnText.right() + rectSize); - } - painter->fillRect(txtRect.x(), txtRect.top() + rectSize / 2, rectSize, rectSize, cY); - txtRect.setX(txtRect.x() + rectSize * 2); - painter->drawText(txtRect, 0, i18nc("Y as in y coordinate", "Y") + QStringLiteral(" (%1-%2)").arg(maximas.at(1).x()).arg(maximas.at(1).y()), - &drawnText); - } - if (wDist > 0) { - if (drawnText.isValid()) { - txtRect.setX(drawnText.right() + rectSize); - } - painter->fillRect(txtRect.x(), txtRect.top() + rectSize / 2, rectSize, rectSize, cW); - txtRect.setX(txtRect.x() + rectSize * 2); - painter->drawText(txtRect, 0, i18n("Width") + QStringLiteral(" (%1-%2)").arg(maximas.at(2).x()).arg(maximas.at(2).y()), &drawnText); - } - if (hDist > 0) { - if (drawnText.isValid()) { - txtRect.setX(drawnText.right() + rectSize); - } - painter->fillRect(txtRect.x(), txtRect.top() + rectSize / 2, rectSize, rectSize, cH); - txtRect.setX(txtRect.x() + rectSize * 2); - painter->drawText(txtRect, 0, i18n("Height") + QStringLiteral(" (%1-%2)").arg(maximas.at(3).x()).arg(maximas.at(3).y()), &drawnText); - } - - // Draw curves - for (int i = 0; i < br.width(); i++) { - mlt_rect rect = m_keyProperties.anim_get_rect(m_inTimeline.toUtf8().constData(), (int)(i * frameFactor) + in); - if (xDist > 0) { - painter->setPen(cX); - int val = (rect.x - xOffset) * maxHeight / xDist; - painter->drawLine(i, maxHeight - val, i, maxHeight); - } - if (yDist > 0) { - painter->setPen(cY); - int val = (rect.y - yOffset) * maxHeight / yDist; - painter->drawLine(i, maxHeight - val, i, maxHeight); - } - if (wDist > 0) { - painter->setPen(cW); - int val = (rect.w - wOffset) * maxHeight / wDist; - painter->drawLine(i, maxHeight - val, i, maxHeight); - } - if (hDist > 0) { - painter->setPen(cH); - int val = (rect.h - hOffset) * maxHeight / hDist; - painter->drawLine(i, maxHeight - val, i, maxHeight); - } - } - if (offset > 1) { - // Overlay limited keyframes curve - cX.setAlpha(255); - cY.setAlpha(255); - cW.setAlpha(255); - cH.setAlpha(255); - mlt_rect rect1 = m_keyProperties.anim_get_rect(m_inTimeline.toUtf8().constData(), in); - int prevPos = 0; - for (int i = offset; i < br.width(); i += offset) { - mlt_rect rect2 = m_keyProperties.anim_get_rect(m_inTimeline.toUtf8().constData(), (int)(i * frameFactor) + in); - if (xDist > 0) { - painter->setPen(cX); - int val1 = (rect1.x - xOffset) * maxHeight / xDist; - int val2 = (rect2.x - xOffset) * maxHeight / xDist; - painter->drawLine(prevPos, maxHeight - val1, i, maxHeight - val2); - } - if (yDist > 0) { - painter->setPen(cY); - int val1 = (rect1.y - yOffset) * maxHeight / yDist; - int val2 = (rect2.y - yOffset) * maxHeight / yDist; - painter->drawLine(prevPos, maxHeight - val1, i, maxHeight - val2); - } - if (wDist > 0) { - painter->setPen(cW); - int val1 = (rect1.w - wOffset) * maxHeight / wDist; - int val2 = (rect2.w - wOffset) * maxHeight / wDist; - painter->drawLine(prevPos, maxHeight - val1, i, maxHeight - val2); - } - if (hDist > 0) { - painter->setPen(cH); - int val1 = (rect1.h - hOffset) * maxHeight / hDist; - int val2 = (rect2.h - hOffset) * maxHeight / hDist; - painter->drawLine(prevPos, maxHeight - val1, i, maxHeight - val2); - } - rect1 = rect2; - prevPos = i; - } - } -} - -QString KeyframeView::getSingleAnimation(int ix, int in, int out, int offset, int limitKeyframes, QPoint maximas, double min, double max) -{ - m_keyProperties.set("kdenlive_import", ""); - int newduration = out - in + offset; - m_keyProperties.anim_get_double("kdenlive_import", 0, newduration); - Mlt::Animation anim = m_keyProperties.get_animation("kdenlive_import"); - double factor = (max - min) / (maximas.y() - maximas.x()); - mlt_rect rect = m_keyProperties.anim_get_rect(m_inTimeline.toUtf8().constData(), in, duration); - double value; - switch (ix) { - case 1: - value = rect.y; - break; - case 2: - value = rect.w; - break; - case 3: - value = rect.h; - break; - default: - value = rect.x; - break; - } - if (maximas.x() > 0) { - value -= maximas.x(); - } - value = value * factor + min; - m_keyProperties.anim_set("kdenlive_import", value, offset, newduration, limitKeyframes > 0 ? mlt_keyframe_smooth : mlt_keyframe_linear); - if (limitKeyframes > 0) { - int step = (out - in) / limitKeyframes; - for (int i = step; i < out; i += step) { - rect = m_keyProperties.anim_get_rect(m_inTimeline.toUtf8().constData(), in + i, duration); - switch (ix) { - case 1: - value = rect.y; - break; - case 2: - value = rect.w; - break; - case 3: - value = rect.h; - break; - default: - value = rect.x; - break; - } - if (maximas.x() > 0) { - value -= maximas.x(); - } - value = value * factor + min; - m_keyProperties.anim_set("kdenlive_import", value, offset + i, newduration, mlt_keyframe_smooth); - } - } else { - int next = m_keyAnim.next_key(in + 1); - while (next < out && next > 0) { - rect = m_keyProperties.anim_get_rect(m_inTimeline.toUtf8().constData(), next, duration); - switch (ix) { - case 1: - value = rect.y; - break; - case 2: - value = rect.w; - break; - case 3: - value = rect.h; - break; - default: - value = rect.x; - break; - } - if (maximas.x() > 0) { - value -= maximas.x(); - } - value = value * factor + min; - m_keyProperties.anim_set("kdenlive_import", value, offset + next - in, newduration, mlt_keyframe_linear); - next = m_keyAnim.next_key(next + 1); - } - } - QString result = anim.serialize_cut(); - m_keyProperties.set("kdenlive_import", (char *)nullptr); - return result; -} - -QString KeyframeView::getOffsetAnimation(int in, int out, int offset, int limitKeyframes, bool allowAnimation, bool positionOnly, - QPoint rectOffset) -{ - m_keyProperties.set("kdenlive_import", ""); - int newduration = out - in + offset; - int pWidth = pCore->getCurrentProfile()->width(); - int pHeight = pCore->getCurrentProfile()->height(); - m_keyProperties.anim_get_double("kdenlive_import", 0, newduration); - Mlt::Animation anim = m_keyProperties.get_animation("kdenlive_import"); - mlt_keyframe_type kftype = (limitKeyframes > 0 && allowAnimation) ? mlt_keyframe_smooth : mlt_keyframe_linear; - mlt_rect rect = m_keyProperties.anim_get_rect(m_inTimeline.toUtf8().constData(), in, duration); - rect.x = (int)rect.x; - rect.y = (int)rect.y; - if (positionOnly) { - rect.x -= rectOffset.x(); - rect.y -= rectOffset.y(); - rect.w = pWidth; - rect.h = pHeight; - rect.o = 100; - } - m_keyProperties.anim_set("kdenlive_import", rect, offset, newduration, kftype); - if (limitKeyframes > 0 && m_keyAnim.key_count() > limitKeyframes) { - int step = (out - in) / limitKeyframes; - for (int i = step; i < out; i += step) { - rect = m_keyProperties.anim_get_rect(m_inTimeline.toUtf8().constData(), in + i, duration); - rect.x = (int)rect.x; - rect.y = (int)rect.y; - if (positionOnly) { - rect.x -= rectOffset.x(); - rect.y -= rectOffset.y(); - rect.w = pWidth; - rect.h = pHeight; - rect.o = 100; - } - m_keyProperties.anim_set("kdenlive_import", rect, offset + i, newduration, kftype); - } - } else { - int pos; - for (int i = 0; i < m_keyAnim.key_count(); ++i) { - m_keyAnim.key_get(i, pos, kftype); - rect = m_keyProperties.anim_get_rect(m_inTimeline.toUtf8().constData(), pos, duration); - rect.x = (int)rect.x; - rect.y = (int)rect.y; - if (positionOnly) { - rect.x -= rectOffset.x(); - rect.y -= rectOffset.y(); - rect.w = pWidth; - rect.h = pHeight; - rect.o = 100; - } - m_keyProperties.anim_set("kdenlive_import", rect, offset + pos - in, newduration, kftype); - } - } - QString result = anim.serialize_cut(); - m_keyProperties.set("kdenlive_import", (char *)nullptr); - return result; -} - -int KeyframeView::mouseOverKeyFrames(const QRectF &br, QPointF pos, double scale) -{ - if (m_keyframeType == NoKeyframe) { - return -1; - } - pos.setX((pos.x() - m_offset) * scale); - int previousEdit = activeKeyframe; - for (int i = 0; i < m_keyAnim.key_count(); ++i) { - int key = m_keyAnim.key_get_frame(i); - if (key < 0) { - key += duration; - } - double value = m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), key, duration - m_offset); - QPointF p = keyframeMap(br, key, value); - p.setX(p.x() * scale); - if (m_keyframeType == GeometryKeyframe) { - p.setY(br.bottom() - br.height() / 2); - } - if ((pos - p).manhattanLength() <= m_handleSize / 2) { - // TODO - /*setToolTip(QLatin1Char('[') + QString::number((GenTime(key, m_fps) - cropStart()).seconds(), 'f', 2) - + i18n("seconds") + QStringLiteral(", ") + QString::number(value, 'f', 1) + ']');*/ - activeKeyframe = key; - if (previousEdit != activeKeyframe) { - updateKeyframes(); - } - return key; - } - if (p.x() > pos.x()) { - break; - } - } - // setToolTip(QString()); - activeKeyframe = -1; - if (previousEdit != activeKeyframe) { - updateKeyframes(); - } - return -1; -} - -double KeyframeView::editedKeyFrameValue() -{ - return m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), activeKeyframe, duration - m_offset); -} - -void KeyframeView::updateKeyFramePos(const QRectF &br, int frame, const double y) -{ - if (!m_keyAnim.is_key(activeKeyframe)) { - return; - } - int prev = m_keyAnim.key_count() <= 1 || m_keyAnim.key_get_frame(0) == activeKeyframe ? 0 : m_keyAnim.previous_key(activeKeyframe - 1) + 1; - prev = qMax(prev, -m_offset); - int next = m_keyAnim.key_count() <= 1 || m_keyAnim.key_get_frame(m_keyAnim.key_count() - 1) == activeKeyframe ? duration - m_offset - 1 - : m_keyAnim.next_key(activeKeyframe + 1) - 1; - if (next < 0) { - next += duration; - } - int newpos = qBound(prev, frame - m_offset, next); - double newval = keyframeUnmap(br, y); - mlt_keyframe_type type = m_keyAnim.keyframe_type(activeKeyframe); - if (m_keyframeType == GeometryKeyframe) { - // Animated rect - mlt_rect rect = m_keyProperties.anim_get_rect(m_inTimeline.toUtf8().constData(), activeKeyframe - m_offset, duration - m_offset); - m_keyProperties.anim_set(m_inTimeline.toUtf8().constData(), rect, newpos, duration - m_offset, type); - } else { - m_keyProperties.anim_set(m_inTimeline.toUtf8().constData(), newval, newpos, duration - m_offset, type); - } - if (activeKeyframe != newpos) { - m_keyAnim.remove(activeKeyframe); - // Move keyframe in other geometries - int cnt = m_keyProperties.count(); - QStringList paramNames; - for (int i = 0; i < cnt; i++) { - paramNames << m_keyProperties.get_name(i); - } - paramNames.removeAll(m_inTimeline); - for (const QString ¶mName : paramNames) { - ParameterInfo info = m_paramInfos.value(paramName); - if (info.max == info.min) { - // this is probably an animated rect - mlt_rect rect = m_keyProperties.anim_get_rect(paramName.toUtf8().constData(), activeKeyframe - m_offset, duration - m_offset); - m_keyProperties.anim_set(paramName.toUtf8().constData(), rect, newpos, duration - m_offset, type); - - } else { - double val = m_keyProperties.anim_get_double(paramName.toUtf8().constData(), activeKeyframe - m_offset, duration - m_offset); - m_keyProperties.anim_set(paramName.toUtf8().constData(), val, newpos, duration - m_offset, type); - } - // Remove kfr at previous position - m_keyAnim = m_keyProperties.get_animation(paramName.toUtf8().constData()); - m_keyAnim.remove(activeKeyframe); - } - m_keyAnim = m_keyProperties.get_animation(m_inTimeline.toUtf8().constData()); - } - if (attachToEnd == activeKeyframe) { - attachToEnd = newpos; - } - activeKeyframe = newpos; - emit updateKeyframes(); -} - -double KeyframeView::getKeyFrameClipHeight(const QRectF &br, const double y) -{ - return keyframeUnmap(br, y); -} - -int KeyframeView::keyframesCount() -{ - if (duration == 0) { - return -1; - } - return m_keyAnim.key_count(); -} - -mlt_keyframe_type KeyframeView::type(int frame) -{ - if (m_keyAnim.is_key(frame)) { - return m_keyAnim.keyframe_type(frame); - } - // no keyframe at position frame, try to get previous key's type - int previous = m_keyAnim.previous_key(frame); - return m_keyAnim.keyframe_type(previous); -} - -void KeyframeView::addKeyframe(int frame, double value, mlt_keyframe_type type) -{ - m_keyProperties.anim_set(m_inTimeline.toUtf8().constData(), value, frame - m_offset, duration - m_offset, type); - // Last keyframe should stick to end - if (frame == duration - 1) { - attachToEnd = frame - m_offset; - } - // Add keyframe in other animations if any - int cnt = m_keyProperties.count(); - QStringList paramNames; - for (int i = 0; i < cnt; i++) { - paramNames << m_keyProperties.get_name(i); - } - paramNames.removeAll(m_inTimeline); - for (const QString ¶mName : paramNames) { - ParameterInfo info = m_paramInfos.value(paramName); - if (info.max == info.min) { - // this is probably an animated rect - mlt_rect rect = m_keyProperties.anim_get_rect(paramName.toUtf8().constData(), frame - m_offset, duration - m_offset); - m_keyProperties.anim_set(paramName.toUtf8().constData(), rect, frame - m_offset, duration - m_offset, type); - - } else { - double val = m_keyProperties.anim_get_double(paramName.toUtf8().constData(), frame - m_offset, duration - m_offset); - m_keyProperties.anim_set(paramName.toUtf8().constData(), val, frame - m_offset, duration - m_offset, type); - } - } -} - -void KeyframeView::addDefaultKeyframe(int frame, mlt_keyframe_type type) -{ - double value = m_keyframeDefault; - if (m_keyAnim.key_count() == 1 && frame != m_keyAnim.key_get_frame(0)) { - value = m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), m_keyAnim.key_get_frame(0), duration - m_offset); - } - m_keyProperties.anim_set(m_inTimeline.toUtf8().constData(), value, frame, duration - m_offset, type); - // Last keyframe should stick to end - if (frame >= duration - 1) { - attachToEnd = frame - m_offset; - } - // Add keyframe in other animations if any - int cnt = m_keyProperties.count(); - QStringList paramNames; - QLocale locale; - for (int i = 0; i < cnt; i++) { - paramNames << m_keyProperties.get_name(i); - } - paramNames.removeAll(m_inTimeline); - for (const QString ¶mName : paramNames) { - ParameterInfo info = m_paramInfos.value(paramName); - if (info.max == info.min) { - // this is probably an animated rect - QString defaultVal = info.defaultValue; - if (defaultVal.contains(QLatin1Char('%'))) { - defaultVal = EffectsController::getStringRectEval(defaultVal).simplified(); - } - mlt_rect rect; - rect.x = locale.toDouble(defaultVal.section(QLatin1Char(' '), 0, 0)); - rect.y = locale.toDouble(defaultVal.section(QLatin1Char(' '), 1, 1)); - rect.w = locale.toDouble(defaultVal.section(QLatin1Char(' '), 2, 2)); - rect.h = locale.toDouble(defaultVal.section(QLatin1Char(' '), 3, 3)); - rect.o = defaultVal.count(QLatin1Char(' ')) > 3 ? locale.toDouble(defaultVal.section(QLatin1Char(' '), 4, 4)) : 1.0; - m_keyProperties.anim_set(paramName.toUtf8().constData(), rect, frame - m_offset, duration - m_offset, type); - - } else { - double val = locale.toDouble(info.defaultValue); - m_keyProperties.anim_set(paramName.toUtf8().constData(), val, frame - m_offset, duration - m_offset, type); - } - } -} - -void KeyframeView::removeKeyframe(int frame) -{ - m_keyAnim.remove(frame); - if (frame == duration - 1 && frame == attachToEnd) { - attachToEnd = -2; - } - // Remove keyframe in other animations if any - int cnt = m_keyProperties.count(); - QStringList paramNames; - for (int i = 0; i < cnt; i++) { - paramNames << m_keyProperties.get_name(i); - } - paramNames.removeAll(m_inTimeline); - for (const QString ¶mName : paramNames) { - m_keyAnim = m_keyProperties.get_animation(paramName.toUtf8().constData()); - m_keyAnim.remove(frame); - } - m_keyAnim = m_keyProperties.get_animation(m_inTimeline.toUtf8().constData()); -} - -QAction *KeyframeView::parseKeyframeActions(const QList &actions) -{ - - mlt_keyframe_type type = m_keyAnim.keyframe_type(activeKeyframe); - for (int i = 0; i < actions.count(); i++) { - if (actions.at(i)->data().toInt() == type) { - return actions.at(i); - } - } - return nullptr; -} - -void KeyframeView::attachKeyframeToEnd(bool attach) -{ - if (attach) { - attachToEnd = activeKeyframe; - } else { - if (attachToEnd != duration - 1) { - // Check if there is a keyframe at end pos, and attach it to end if it is the case - if (m_keyAnim.is_key(duration - 1)) { - attachToEnd = duration - 1; - } - } else { - // We want to detach last keyframe from end - attachToEnd = -2; - } - } - emit updateKeyframes(); -} - -void KeyframeView::editKeyframeType(int type) -{ - if (m_keyAnim.is_key(activeKeyframe)) { - // This is a keyframe - double val = m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), activeKeyframe, duration - m_offset); - m_keyProperties.anim_set(m_inTimeline.toUtf8().constData(), val, activeKeyframe, duration - m_offset, (mlt_keyframe_type)type); - } -} - -bool KeyframeView::activeParam(const QString &name) const -{ - return name == m_inTimeline; -} - -const QString KeyframeView::serialize(const QString &name, bool rectAnimation) -{ - if (!name.isEmpty()) { - m_keyAnim = m_keyProperties.get_animation(name.toUtf8().constData()); - } - if (attachToEnd == -2 || rectAnimation) { - return m_keyAnim.serialize_cut(); - } - mlt_keyframe_type type; - QString key; - QLocale locale; - QStringList result; - int pos; - for (int i = 0; i < m_keyAnim.key_count(); ++i) { - m_keyAnim.key_get(i, pos, type); - double val = m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), pos, duration - m_offset); - if (pos >= attachToEnd) { - pos = qMin(pos - (duration - m_offset), -1); - } - key = QString::number(pos); - switch (type) { - case mlt_keyframe_discrete: - key.append(QStringLiteral("|=")); - break; - case mlt_keyframe_smooth: - key.append(QStringLiteral("~=")); - break; - default: - key.append(QStringLiteral("=")); - break; - } - key.append(locale.toString(val)); - result << key; - } - if (!name.isEmpty()) { - m_keyAnim = m_keyProperties.get_animation(m_inTimeline.toUtf8().constData()); - } - return result.join(QLatin1Char(';')); -} - -QList KeyframeView::loadKeyframes(const QString &data) -{ - QList result; - m_keyframeType = NoKeyframe; - m_inTimeline = QStringLiteral("imported"); - m_keyProperties.set(m_inTimeline.toUtf8().constData(), data.toUtf8().constData()); - // We need to initialize with length so that negative keyframes are correctly interpreted - m_keyProperties.anim_get_rect(m_inTimeline.toUtf8().constData(), 0, duration); - m_keyAnim = m_keyProperties.get_animation(m_inTimeline.toUtf8().constData()); - duration = m_keyAnim.length(); - // calculate minimas / maximas - int max = m_keyAnim.key_count(); - if (max == 0) { - // invalid geometry - result << QPoint() << QPoint() << QPoint() << QPoint(); - return result; - } - int frame = m_keyAnim.key_get_frame(0); - mlt_rect rect = m_keyProperties.anim_get_rect(m_inTimeline.toUtf8().constData(), frame, duration); - QPoint pX(rect.x, rect.x); - QPoint pY(rect.y, rect.y); - QPoint pW(rect.w, rect.w); - QPoint pH(rect.h, rect.h); - for (int i = 1; i < max; i++) { - frame = m_keyAnim.key_get_frame(i); - rect = m_keyProperties.anim_get_rect(m_inTimeline.toUtf8().constData(), frame, duration); - // Check x bounds - if (rect.x < pX.x()) { - pX.setX(rect.x); - } - if (rect.x > pX.y()) { - pX.setY(rect.x); - } - // Check y bounds - if (rect.y < pY.x()) { - pY.setX(rect.y); - } - if (rect.y > pY.y()) { - pY.setY(rect.y); - } - // Check w bounds - if (rect.w < pW.x()) { - pW.setX(rect.w); - } - if (rect.w > pW.y()) { - pW.setY(rect.w); - } - // Check h bounds - if (rect.h < pH.x()) { - pH.setX(rect.h); - } - if (rect.h > pH.y()) { - pH.setY(rect.h); - } - } - result << pX << pY << pW << pH; - return result; -} - -bool KeyframeView::loadKeyframes(const QLocale &locale, const QDomElement &effect, int cropStart, int length) -{ - m_keyframeType = NoKeyframe; - duration = length; - m_inTimeline.clear(); - m_notInTimeline.clear(); - // reset existing properties - int max = m_keyProperties.count(); - for (int i = max - 1; i >= 0; i--) { - m_keyProperties.set(m_keyProperties.get_name(i), (char *)nullptr); - } - attachToEnd = -2; - m_useOffset = effect.attribute(QStringLiteral("kdenlive:sync_in_out")) != QLatin1String("1"); - m_offset = effect.attribute(QStringLiteral("in")).toInt() - cropStart; - QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter")); - QStringList keyframeTypes; - keyframeTypes << QStringLiteral("keyframe") << QStringLiteral("simplekeyframe") << QStringLiteral("geometry") << QStringLiteral("animatedrect") - << QStringLiteral("animated"); - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - if (e.isNull()) { - continue; - } - QString type = e.attribute(QStringLiteral("type")); - if (!keyframeTypes.contains(type)) { - continue; - } - QString paramName = e.attribute(QStringLiteral("name")); - ParameterInfo info; - info.factor = locale.toDouble(e.attribute(QStringLiteral("factor"))); - info.max = locale.toDouble(e.attribute(QStringLiteral("max"))); - info.min = locale.toDouble(e.attribute(QStringLiteral("min"))); - info.defaultValue = e.attribute(QStringLiteral("default")); - if (info.factor == 0) { - info.factor = 1; - } - m_paramInfos.insert(paramName, info); - if (e.hasAttribute(QStringLiteral("notintimeline"))) { - // This param should not be drawn in timeline - m_notInTimeline << paramName; - } else { - if (type == QLatin1String("keyframe")) { - m_keyframeType = NormalKeyframe; - } else if (type == QLatin1String("simplekeyframe")) { - m_keyframeType = SimpleKeyframe; - } else if (type == QLatin1String("geometry") || type == QLatin1String("animatedrect")) { - m_keyframeType = GeometryKeyframe; - } else if (type == QLatin1String("animated")) { - m_keyframeType = AnimatedKeyframe; - } - if (!e.hasAttribute(QStringLiteral("intimeline")) || e.attribute(QStringLiteral("intimeline")) == QLatin1String("1")) { - // Active parameter - m_keyframeMin = info.min; - m_keyframeMax = info.max; - m_keyframeDefault = locale.toDouble(info.defaultValue); - m_keyframeFactor = info.factor; - attachToEnd = checkNegatives(e.attribute(QStringLiteral("value")).toUtf8().constData(), duration - m_offset); - m_inTimeline = paramName; - } - } - // parse keyframes - QString value = e.attribute(QStringLiteral("value")); - if (value.isEmpty()) { - value = e.attribute(QStringLiteral("default")); - } - switch (m_keyframeType) { - case GeometryKeyframe: - m_keyProperties.set(paramName.toUtf8().constData(), value.toUtf8().constData()); - m_keyProperties.anim_get_rect(paramName.toUtf8().constData(), 0, length); - break; - case AnimatedKeyframe: - m_keyProperties.set(paramName.toUtf8().constData(), value.toUtf8().constData()); - // We need to initialize with length so that negative keyframes are correctly interpreted - m_keyProperties.anim_get_double(paramName.toUtf8().constData(), 0, length); - break; - default: - m_keyProperties.set(m_inTimeline.toUtf8().constData(), e.attribute(m_inTimeline.toUtf8().constData()).toUtf8().constData()); - m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), 0, length); - } - if (paramName == m_inTimeline) { - m_keyAnim = m_keyProperties.get_animation(m_inTimeline.toUtf8().constData()); - if (m_keyAnim.next_key(activeKeyframe) <= activeKeyframe) { - activeKeyframe = -1; - } - } - } - return (!m_inTimeline.isEmpty()); -} - -void KeyframeView::setOffset(int frames) -{ - if (duration == 0 || !m_keyAnim.is_valid()) { - return; - } - if (m_keyAnim.is_key(-m_offset)) { - mlt_keyframe_type type = m_keyAnim.keyframe_type(-m_offset); - double value = m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), -m_offset, duration - m_offset); - m_keyAnim.remove(-m_offset); - if (activeKeyframe == -m_offset) { - activeKeyframe -= frames; - } - m_offset -= frames; - m_keyProperties.anim_set(m_inTimeline.toUtf8().constData(), value, -m_offset, duration - m_offset, type); - // addKeyframe(-m_offset, value, type); - } else { - m_offset -= frames; - } - // double value = m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), 0, duration - m_offset); - //} -} - -// static -int KeyframeView::checkNegatives(const QString &data, int maxDuration) -{ - int result = -2; - QStringList frames = data.split(QLatin1Char(';')); - for (int i = 0; i < frames.count(); i++) { - if (frames.at(i).startsWith(QLatin1String("-"))) { - // We found a negative kfr - QString sub = frames.at(i).section(QLatin1Char('='), 0, 0); - if (!sub.at(sub.length() - 1).isDigit()) { - // discrete or smooth keyframe, we need to remove the tag (| or ~) - sub.chop(1); - } - int negPos = sub.toInt() + maxDuration; - if (result == -2 || result > negPos) { - result = negPos; - } - } - } - return result; -} - -void KeyframeView::reset() -{ - if (m_keyframeType == NoKeyframe) { - // nothing to do - return; - } - m_keyframeType = NoKeyframe; - duration = 0; - attachToEnd = -2; - activeKeyframe = -1; - m_inTimeline.clear(); - m_notInTimeline.clear(); - int max = m_keyProperties.count(); - for (int i = max - 1; i >= 0; i--) { - m_keyProperties.set(m_keyProperties.get_name(i), (char *)nullptr); - } - emit updateKeyframes(); -} - -// static -QString KeyframeView::cutAnimation(const QString &animation, int start, int duration, int fullduration, bool doCut) -{ - Mlt::Properties props; - props.set("keyframes", animation.toUtf8().constData()); - props.anim_get_double("keyframes", 0, fullduration); - Mlt::Animation anim = props.get_animation("keyframes"); - if (start > 0 && !anim.is_key(start)) { - // insert new keyframe at start - double value = props.anim_get_double("keyframes", start, fullduration); - int previous = anim.previous_key(start); - mlt_keyframe_type type = anim.keyframe_type(previous); - props.anim_set("keyframes", value, start, fullduration, type); - } - if (!anim.is_key(start + duration)) { - double value = props.anim_get_double("keyframes", start + duration, fullduration); - int previous = anim.previous_key(start + duration); - mlt_keyframe_type type = anim.keyframe_type(previous); - props.anim_set("keyframes", value, start + duration, fullduration, type); - } - if (!doCut) { - return anim.serialize_cut(); - } - return anim.serialize_cut(start, start + duration); -} - -// static -const QString KeyframeView::addBorderKeyframes(const QString &animation, int start, int duration) -{ - bool modified = false; - Mlt::Properties props; - props.set("keyframes", animation.toUtf8().constData()); - props.anim_get_double("keyframes", 0, start + duration); - Mlt::Animation anim = props.get_animation("keyframes"); - if (!anim.is_key(start)) { - double value = props.anim_get_double("keyframes", start, start + duration); - int previous = anim.previous_key(start); - mlt_keyframe_type type = anim.keyframe_type(previous); - props.anim_set("keyframes", value, start, start + duration, type); - modified = true; - } - if (!anim.is_key(start + duration)) { - double value = props.anim_get_double("keyframes", start + duration, start + duration); - int previous = anim.previous_key(start + duration); - mlt_keyframe_type type = anim.keyframe_type(previous); - props.anim_set("keyframes", value, start + duration, start + duration, type); - modified = true; - } - if (modified) { - return anim.serialize_cut(); - } - return animation; -} - -// static -QString KeyframeView::switchAnimation(const QString &animation, int newPos, int oldPos, int newDuration, int oldDuration, bool isRect) -{ - Mlt::Properties props; - props.set("keyframes", animation.toUtf8().constData()); - props.anim_get_double("keyframes", 0, oldDuration); - Mlt::Animation anim = props.get_animation("keyframes"); - if (anim.is_key(oldPos)) { - // insert new keyframe at start - if (isRect) { - mlt_rect rect = props.anim_get_rect("keyframes", oldPos, oldDuration); - props.anim_set("keyframes", rect, newPos, newDuration, anim.keyframe_type(oldPos)); - anim.remove(oldPos); - } else { - double value = props.anim_get_double("keyframes", oldPos, oldDuration); - props.anim_set("keyframes", value, newPos, newDuration, anim.keyframe_type(oldPos)); - anim.remove(oldPos); - } - } - return anim.serialize_cut(); - // return anim.serialize_cut(start, start + duration); -} - -/* -void KeyframeView::updateAnimatedKeyframes(QDomElement effect, int paramIndex, ItemInfo oldInfo) -{ - QDomElement param = effect.elementsByTagName("parameter").item(paramIndex).toElement(); - int offset = oldInfo.cropStart.frames(m_fps); - if (offset > 0) { - for(int i = 0; i < m_keyAnim.key_count(); ++i){ - int oldPos = m_keyAnim.key_get_frame(i); - int newPos = oldPos + offset; - m_keyAnim.remove(oldPos); - m_keyProperties.anim_set(m_inTimeline.toUtf8().constData(), m_keyProperties.anim_get_double(m_inTimeline.toUtf8().constData(), oldPos), newPos, 0, -m_keyAnim.keyframe_type(i)); - } - } - QString result = m_keyAnim.serialize_cut(); - param.setAttribute("value", result); -}*/ diff --git a/src/timeline/keyframeview.h b/src/timeline/keyframeview.h deleted file mode 100644 index 67f3b4b06..000000000 --- a/src/timeline/keyframeview.h +++ /dev/null @@ -1,135 +0,0 @@ -/* -Copyright (C) 2012 Till Theato -Copyright (C) 2014 Jean-Baptiste Mardelle -This file is part of Kdenlive. See www.kdenlive.org. - -This program 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) version 3 or any later version -accepted by the membership of KDE e.V. (or its successor approved -by the membership of KDE e.V.), which shall act as a proxy -defined in Section 14 of version 3 of the license. - -This program 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 this program. If not, see . -*/ - -#ifndef KEYFRAMEVIEW_H -#define KEYFRAMEVIEW_H - -#include "definitions.h" -#include "gentime.h" - -#include "mlt++/MltAnimation.h" -#include "mlt++/MltProperties.h" - -class QAction; - -/** - * @class KeyframeView - * @brief Provides functionality for displaying and managing animation keyframes in timeline. - * - */ - -class KeyframeView : public QObject -{ - Q_OBJECT - -public: - enum KEYFRAMETYPE { NoKeyframe = 0, SimpleKeyframe, NormalKeyframe, GeometryKeyframe, AnimatedKeyframe }; - - explicit KeyframeView(int handleSize, QObject *parent = nullptr); - virtual ~KeyframeView(); - - /** The position of the currently active keyframe */ - int activeKeyframe; - /** The position of the currently active keyframe before it was moved */ - int originalKeyframe; - /** @brief The keyframe position from which keyframes will be attached to end (-1 = disabled). */ - int attachToEnd; - /** @brief Effect duration, must be updated on resize. */ - int duration; - - /** @brief Move the selected keyframe (does not influence the effect, only the display in timeline). - * @param br the bounding rect for effect drawing - * @param frame new Position - * @param y new Value */ - void updateKeyFramePos(const QRectF &br, int frame, const double y); - double getKeyFrameClipHeight(const QRectF &br, const double y); - /** @brief Returns the number of keyframes the selected effect has, -1 if none. */ - int keyframesCount(); - double editedKeyFrameValue(); - void editKeyframeType(int type); - void attachKeyframeToEnd(bool attach); - mlt_keyframe_type type(int frame); - void removeKeyframe(int frame); - void addKeyframe(int frame, double value, mlt_keyframe_type type); - void addDefaultKeyframe(int frame, mlt_keyframe_type type); - const QString serialize(const QString &name = QString(), bool rectAnimation = false); - /** @brief Loads a rect animation and returns minimas/maximas for x,y,w,h **/ - QList loadKeyframes(const QString &data); - bool loadKeyframes(const QLocale &locale, const QDomElement &e, int cropStart, int length); - void reset(); - /** @brief Draw the keyframes of a clip - * @param painter The painter device for the clip - */ - void drawKeyFrames(const QRectF &br, int length, bool active, QPainter *painter, const QTransform &transformation); - /** @brief Draw the x, y, w, h channels of an animated geometry */ - void drawKeyFrameChannels(const QRectF &br, int in, int out, QPainter *painter, const QList &maximas, int limitKeyframes, const QColor &textColor); - int mouseOverKeyFrames(const QRectF &br, QPointF pos, double scale); - void showMenu(QWidget *parent, QPoint pos); - QAction *parseKeyframeActions(const QList &actions); - static QString cutAnimation(const QString &animation, int start, int duration, int fullduration, bool doCut = true); - /** @brief when an animation is resized, update in / out point keyframes */ - static QString switchAnimation(const QString &animation, int newPos, int oldPos, int newDuration, int oldDuration, bool isRect); - /** @brief when loading an animation from a serialized string, check where is the first negative keyframe) */ - static int checkNegatives(const QString &data, int maxDuration); - /** @brief Add keyframes at start / end points if not existing */ - static const QString addBorderKeyframes(const QString &animation, int start, int duration); - /** @brief returns true if currently edited parameter name is name */ - bool activeParam(const QString &name) const; - /** @brief Sets a temporary offset for drawing keyframes when resizing clip start */ - void setOffset(int frames); - /** @brief Returns a copy of the original anim, with a crop zone (in/out), frame offset, max number of keyframes, and value mapping */ - QString getSingleAnimation(int ix, int in, int out, int offset, int limitKeyframes, QPoint maximas, double min, double max); - /** @brief Returns a copy of the original anim, with a crop zone (in/out) and frame offset */ - QString getOffsetAnimation(int in, int out, int offset, int limitKeyframes, bool allowAnimation, bool positionOnly, QPoint rectOffset); - -private: - Mlt::Properties m_keyProperties; - Mlt::Animation m_keyAnim; - KEYFRAMETYPE m_keyframeType; - QString m_inTimeline; - double m_keyframeDefault; - double m_keyframeMin; - double m_keyframeMax; - double m_keyframeFactor; - int m_handleSize; - bool m_useOffset; - int m_offset; - QStringList m_notInTimeline; - double keyframeUnmap(const QRectF &br, double y); - double keyframeMap(const QRectF &br, double value); - QPointF keyframeMap(const QRectF &br, int frame, double value); - QPointF keyframePoint(const QRectF &br, int index); - QPointF keyframePoint(const QRectF &br, int frame, double value, double factor, double min, double max); - struct ParameterInfo - { - double factor; - double min; - double max; - QString defaultValue; - }; - QMap m_paramInfos; - -signals: - void updateKeyframes(const QRectF &r = QRectF()); -}; - -#endif diff --git a/src/timeline/managers/abstracttoolmanager.cpp b/src/timeline/managers/abstracttoolmanager.cpp deleted file mode 100644 index 4b7e513ef..000000000 --- a/src/timeline/managers/abstracttoolmanager.cpp +++ /dev/null @@ -1,118 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "abstracttoolmanager.h" - -#include "doc/docundostack.hpp" -#include "timeline/customtrackview.h" -#include - -AbstractToolManager::AbstractToolManager(ToolManagerType type, CustomTrackView *view, std::shared_ptr commandStack) - : QObject() - , m_managerType(type) - , m_view(view) - , m_commandStack(std::move(commandStack)) -{ -} - -AbstractToolManager::ToolManagerType AbstractToolManager::type() const -{ - return m_managerType; -} - -bool AbstractToolManager::mouseMove(QMouseEvent *, int, int) -{ - return true; -} - -bool AbstractToolManager::isCurrent(OperationType type) const -{ - switch (type) { - case MoveOperation: - return m_managerType == MoveType; - break; - case ResizeStart: - case ResizeEnd: - return m_managerType == ResizeType; - break; - case RollingStart: - case RollingEnd: - case RippleStart: - case RippleEnd: - return m_managerType == TrimType; - break; - case MoveGuide: - return m_managerType == GuideType; - break; - case Spacer: - return m_managerType == SpacerType; - break; - default: - return m_managerType == SelectType; - break; - } -} - -AbstractToolManager::ToolManagerType AbstractToolManager::getTool(OperationType type) const -{ - switch (type) { - case MoveOperation: - return MoveType; - break; - case ResizeStart: - case ResizeEnd: - return ResizeType; - break; - case RollingStart: - case RollingEnd: - case RippleStart: - case RippleEnd: - return TrimType; - break; - case MoveGuide: - return GuideType; - break; - case Spacer: - return SpacerType; - break; - default: - return SelectType; - break; - } -} - -void AbstractToolManager::updateTimelineItems() -{ -} - -void AbstractToolManager::initTool(double) -{ -} - -void AbstractToolManager::enterEvent(int, double) -{ -} - -void AbstractToolManager::leaveEvent() -{ -} - -void AbstractToolManager::closeTool() -{ -} diff --git a/src/timeline/managers/abstracttoolmanager.h b/src/timeline/managers/abstracttoolmanager.h deleted file mode 100644 index 53a7bc67d..000000000 --- a/src/timeline/managers/abstracttoolmanager.h +++ /dev/null @@ -1,65 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef ABSTRACTTOOLMANAGER_H -#define ABSTRACTTOOLMANAGER_H - -/** - * @namespace AbstractToolManager - * @brief Base class for timeline tools. - */ - -#include "definitions.h" -#include -#include - -class CustomTrackView; -class DocUndoStack; -class QGraphicsItem; - -class AbstractToolManager : public QObject -{ - Q_OBJECT - -public: - enum ToolManagerType { TrimType = 0, SpacerType, MoveType, ResizeType, RazorType, SelectType, GuideType }; - explicit AbstractToolManager(ToolManagerType type, CustomTrackView *view, std::shared_ptr commandStack); - virtual bool mousePress(QMouseEvent *event, const ItemInfo &info = ItemInfo(), const QList &list = QList()) = 0; - virtual bool mouseMove(QMouseEvent *event, int pos = 0, int track = -1); - virtual void mouseRelease(QMouseEvent *event, GenTime pos = GenTime()) = 0; - virtual void enterEvent(int pos, double trackHeight); - virtual void leaveEvent(); - virtual void initTool(double trackHeight); - virtual void closeTool(); - /** @brief returns true if the current tool is adapted to the operation mode */ - bool isCurrent(OperationType type) const; - /** @brief returns the tool adapted to the operation mode */ - AbstractToolManager::ToolManagerType getTool(OperationType type) const; - AbstractToolManager::ToolManagerType type() const; - -public slots: - virtual void updateTimelineItems(); - -protected: - ToolManagerType m_managerType; - CustomTrackView *m_view; - std::shared_ptr m_commandStack; -}; - -#endif diff --git a/src/timeline/managers/guidemanager.cpp b/src/timeline/managers/guidemanager.cpp deleted file mode 100644 index 2f507dc9c..000000000 --- a/src/timeline/managers/guidemanager.cpp +++ /dev/null @@ -1,94 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "guidemanager.h" -#include "doc/docundostack.hpp" -#include "timeline/abstractclipitem.h" -#include "timeline/customtrackview.h" -#include "timeline/timelinecommands.h" - -#include -#include -#include - -GuideManager::GuideManager(CustomTrackView *view, std::shared_ptr commandStack) - : AbstractToolManager(GuideType, view, std::move(commandStack)) - , m_dragGuide(nullptr) -{ -} - -bool GuideManager::mousePress(QMouseEvent *, const ItemInfo &info, const QList &list) -{ - Q_UNUSED(info); - m_collisionList = list; - // if a guide and a clip were pressed, just select the guide - for (int i = 0; i < m_collisionList.count(); ++i) { - if (m_collisionList.at(i)->type() == GUIDEITEM) { - // a guide item was pressed - m_dragGuide = static_cast(m_collisionList.at(i)); - m_dragGuide->setFlag(QGraphicsItem::ItemIsMovable, true); - m_view->setOperationMode(MoveGuide); - // deselect all clips so that only the guide will move - m_view->clearSelection(); - m_view->updateSnapPoints(nullptr); - return true; - } - } - return false; -} - -bool GuideManager::mouseMove(QMouseEvent *event, int, int) -{ - event->accept(); - return false; -} - -void GuideManager::mouseRelease(QMouseEvent *, GenTime pos) -{ - m_view->setCursor(Qt::ArrowCursor); - m_dragGuide->setFlag(QGraphicsItem::ItemIsMovable, false); - GenTime newPos = GenTime(m_dragGuide->pos().x(), m_view->fps()); - if (newPos != m_dragGuide->position()) { - EditGuideCommand *command = new EditGuideCommand(m_view, m_dragGuide->position(), m_dragGuide->label(), newPos, m_dragGuide->label(), false); - m_commandStack->push(command); - m_dragGuide->updateGuide(GenTime(m_dragGuide->pos().x(), m_view->fps())); - m_view->guidesUpdated(); - m_dragGuide = nullptr; - AbstractClipItem *dragItem = m_view->dragItem(); - if (dragItem) { - dragItem->setMainSelectedClip(false); - } - dragItem = nullptr; - m_view->setOperationMode(None); - } - m_view->sortGuides(); - m_collisionList.clear(); - Q_UNUSED(pos); -} - -// static -void GuideManager::checkOperation(const QList &items, CustomTrackView *parent, QMouseEvent * /*event*/, OperationType &operationMode, - bool &abort) -{ - if (items.count() == 1 && items.at(0)->type() == GUIDEITEM) { - operationMode = MoveGuide; - parent->setCursor(Qt::SplitHCursor); - abort = true; - } -} diff --git a/src/timeline/managers/guidemanager.h b/src/timeline/managers/guidemanager.h deleted file mode 100644 index 895d6420f..000000000 --- a/src/timeline/managers/guidemanager.h +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef GUIDEMANAGER_H -#define GUIDEMANAGER_H - -#include "abstracttoolmanager.h" - -class QGraphicsItem; -class QMouseEvent; -class CustomTrackView; -class Guide; -class DocUndoStack; - -/** - * @namespace GuideManager - * @brief Provides convenience methods to handle timeline guides. - */ - -class GuideManager : public AbstractToolManager -{ - Q_OBJECT - -public: - explicit GuideManager(CustomTrackView *view, std::shared_ptr commandStack); - bool mousePress(QMouseEvent *event, const ItemInfo &info = ItemInfo(), const QList &list = QList()) override; - void mouseRelease(QMouseEvent *event, GenTime pos = GenTime()) override; - bool mouseMove(QMouseEvent *event, int pos, int) override; - /** @brief Check if a guide operation is applicable on items under mouse. - * @param items The list of items under mouse - * @param operationMode Will be set to MoveGuide if applicable - * @param abort Will be set to true if an operation matched and the items list should not be tested for further operation modes - **/ - static void checkOperation(const QList &items, CustomTrackView *parent, QMouseEvent * /*event*/, OperationType &operationMode, - bool &abort); - -private: - QList m_collisionList; - Guide *m_dragGuide; -}; - -#endif diff --git a/src/timeline/managers/movemanager.cpp b/src/timeline/managers/movemanager.cpp deleted file mode 100644 index 27b5cc073..000000000 --- a/src/timeline/managers/movemanager.cpp +++ /dev/null @@ -1,400 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "movemanager.h" -#include "doc/docundostack.hpp" -#include "kdenlivesettings.h" -#include "timeline/abstractgroupitem.h" -#include "timeline/clipitem.h" -#include "timeline/customtrackview.h" -#include "timeline/timelinecommands.h" -#include "timeline/transition.h" -#include "timeline/transitionhandler.h" - -#include -#include -#include -#include - -MoveManager::MoveManager(TransitionHandler *handler, CustomTrackView *view, std::shared_ptr commandStack) - : AbstractToolManager(MoveType, view, commandStack) - , m_transitionHandler(handler) - , m_scrollOffset(0) - , m_scrollTrigger(QFontMetrics(view->font()).averageCharWidth() * 3) - , m_dragMoved(false) -{ - connect(&m_scrollTimer, &QTimer::timeout, this, &MoveManager::slotCheckMouseScrolling); - m_scrollTimer.setInterval(100); - m_scrollTimer.setSingleShot(true); -} - -bool MoveManager::mousePress(QMouseEvent *event, const ItemInfo &info, const QList &) -{ - m_view->setCursor(Qt::ClosedHandCursor); - m_dragMoved = false; - m_clickPoint = event->pos(); - m_dragItemInfo = info; - m_view->setOperationMode(MoveOperation); - return true; -} - -bool MoveManager::mouseMove(QMouseEvent *event, int, int) -{ - if (!m_dragMoved && ((event->buttons() & Qt::LeftButton) != 0u)) { - if ((m_clickPoint - event->pos()).manhattanLength() < QApplication::startDragDistance()) { - event->ignore(); - return true; - } - m_dragMoved = true; - } - if (m_dragItemInfo.isValid()) { - if (event->pos().x() < m_scrollTrigger) { - m_scrollOffset = -30; - m_scrollTimer.start(); - } else if (m_view->viewport()->width() - event->pos().x() < m_scrollTrigger) { - m_scrollOffset = 30; - m_scrollTimer.start(); - } else if (m_scrollTimer.isActive()) { - m_scrollTimer.stop(); - } - event->accept(); - return false; - } - return true; -} - -void MoveManager::mouseRelease(QMouseEvent *, GenTime pos) -{ - Q_UNUSED(pos); - if (m_scrollTimer.isActive()) { - m_scrollTimer.stop(); - } - m_view->setCursor(Qt::OpenHandCursor); - if (!m_dragMoved) { - return; - } - AbstractClipItem *dragItem = m_view->dragItem(); - if ((dragItem == nullptr) || !m_dragItemInfo.isValid() || m_view->operationMode() == WaitingForConfirm) { - // No move performed - m_view->setOperationMode(None); - return; - } - ItemInfo info = dragItem->info(); - if (dragItem->parentItem() == nullptr) { - // we are moving one clip, easy - if (dragItem->type() == AVWidget && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) { - ClipItem *item = static_cast(dragItem); - bool success = true; - if (success) { - auto *moveCommand = new QUndoCommand(); - moveCommand->setText(i18n("Move clip")); - if (item->hasVisibleVideo()) { - new RefreshMonitorCommand(m_view, QList() << info << m_dragItemInfo, false, true, moveCommand); - } - QList excluded; - excluded << info; - item->setItemLocked(true); - // item->setEnabled(false); - ItemInfo initialClip = m_dragItemInfo; - if (m_view->sceneEditMode() == TimelineMode::InsertEdit) { - m_view->cutTimeline(info.startPos.frames(m_view->fps()), excluded, QList(), moveCommand, info.track); - new AddSpaceCommand(m_view, info, excluded, true, moveCommand, true); - bool isLastClip = m_view->isLastClip(info); - if (!isLastClip && info.track == m_dragItemInfo.track && info.startPos < m_dragItemInfo.startPos) { - // remove offset to allow finding correct clip to move - initialClip.startPos += m_dragItemInfo.cropDuration; - initialClip.endPos += m_dragItemInfo.cropDuration; - } - } else if (m_view->sceneEditMode() == TimelineMode::OverwriteEdit) { - m_view->extractZone(QPoint(info.startPos.frames(m_view->fps()), info.endPos.frames(m_view->fps())), false, excluded, moveCommand, - info.track); - } - bool isLocked = m_view->getTrackInfo(item->track()).isLocked; - new MoveClipCommand(m_view, initialClip, info, true, true, moveCommand); - - // Also move automatic transitions (on lower track) - Transition *startTransition = m_view->getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track); - ItemInfo startTrInfo; - ItemInfo newStartTrInfo; - bool moveStartTrans = false; - bool moveEndTrans = false; - if ((startTransition != nullptr) && startTransition->isAutomatic()) { - startTrInfo = startTransition->info(); - newStartTrInfo = startTrInfo; - newStartTrInfo.track = info.track; - newStartTrInfo.startPos = info.startPos; - // newStartTrInfo.cropDuration = newStartTrInfo.endPos - info.startPos; - if (m_dragItemInfo.track == info.track /*&& !item->baseClip()->isTransparent()*/ && - (m_view->getClipItemAtEnd(newStartTrInfo.endPos, startTransition->transitionEndTrack()) != nullptr)) { - // transition matches clip end on lower track, resize it - newStartTrInfo.cropDuration = newStartTrInfo.endPos - newStartTrInfo.startPos; - } else { - // move transition with clip - newStartTrInfo.endPos = newStartTrInfo.endPos + (newStartTrInfo.startPos - startTrInfo.startPos); - } - if (newStartTrInfo.startPos < newStartTrInfo.endPos) { - moveStartTrans = true; - } - } - if (startTransition == nullptr || startTransition->endPos() < m_dragItemInfo.endPos) { - // Check if there is a transition at clip end - Transition *tr = m_view->getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track); - if ((tr != nullptr) && tr->isAutomatic()) { - ItemInfo trInfo = tr->info(); - ItemInfo newTrInfo = trInfo; - newTrInfo.track = info.track; - newTrInfo.endPos = dragItem->endPos(); - // TODO - if (m_dragItemInfo.track == info.track /*&& !item->baseClip()->isTransparent()*/ && - (m_view->getClipItemAtStart(trInfo.startPos, tr->transitionEndTrack()) != nullptr)) { - // transition start should stay the same, duration changes - newTrInfo.cropDuration = newTrInfo.endPos - newTrInfo.startPos; - } else { - // transition start should be moved - newTrInfo.startPos = newTrInfo.startPos + (newTrInfo.endPos - trInfo.endPos); - } - if (newTrInfo.startPos < newTrInfo.endPos) { - moveEndTrans = true; - if (moveStartTrans) { - // we have to move both transitions, remove the start one so that there is no collision - new AddTransitionCommand(m_view, startTrInfo, startTransition->transitionEndTrack(), startTransition->toXML(), true, true, - moveCommand); - } - m_view->adjustTimelineTransitions(m_view->sceneEditMode(), tr, moveCommand); - if (tr->updateKeyframes(trInfo, newTrInfo)) { - QDomElement old = tr->toXML(); - QDomElement xml = old.cloneNode().toElement(); - m_transitionHandler->updateTransition(xml.attribute(QStringLiteral("tag")), xml.attribute(QStringLiteral("tag")), - xml.attribute(QStringLiteral("transition_btrack")).toInt(), - xml.attribute(QStringLiteral("transition_atrack")).toInt(), newTrInfo.startPos, - newTrInfo.endPos, xml); - new EditTransitionCommand(m_view, tr->track(), tr->startPos(), old, xml, false, moveCommand); - } - new MoveTransitionCommand(m_view, trInfo, newTrInfo, true, false, moveCommand); - if (moveStartTrans) { - // re-add transition in correct place - int transTrack = startTransition->transitionEndTrack(); - if (m_dragItemInfo.track != info.track && !startTransition->forcedTrack()) { - transTrack = m_view->getPreviousVideoTrack(info.track); - } - m_view->adjustTimelineTransitions(m_view->sceneEditMode(), startTransition, moveCommand); - if (startTransition->updateKeyframes(startTrInfo, newStartTrInfo)) { - QDomElement old = startTransition->toXML(); - QDomElement xml = startTransition->toXML(); - m_transitionHandler->updateTransition(xml.attribute(QStringLiteral("tag")), xml.attribute(QStringLiteral("tag")), - xml.attribute(QStringLiteral("transition_btrack")).toInt(), - xml.attribute(QStringLiteral("transition_atrack")).toInt(), newStartTrInfo.startPos, - newStartTrInfo.endPos, xml); - } - new AddTransitionCommand(m_view, newStartTrInfo, transTrack, startTransition->toXML(), false, true, moveCommand); - } - } - } - } - - if (moveStartTrans && !moveEndTrans) { - m_view->adjustTimelineTransitions(m_view->sceneEditMode(), startTransition, moveCommand); - if (startTransition->updateKeyframes(startTrInfo, newStartTrInfo)) { - QDomElement old = startTransition->toXML(); - QDomElement xml = old.cloneNode().toElement(); - m_transitionHandler->updateTransition(xml.attribute(QStringLiteral("tag")), xml.attribute(QStringLiteral("tag")), - xml.attribute(QStringLiteral("transition_btrack")).toInt(), - xml.attribute(QStringLiteral("transition_atrack")).toInt(), newStartTrInfo.startPos, - newStartTrInfo.endPos, xml); - new EditTransitionCommand(m_view, startTransition->track(), startTransition->startPos(), old, xml, false, moveCommand); - } - new MoveTransitionCommand(m_view, startTrInfo, newStartTrInfo, true, false, moveCommand); - } - // Also move automatic transitions (on upper track) - Transition *tr = m_view->getTransitionItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track + 1); - if (m_dragItemInfo.track == info.track && (tr != nullptr) && tr->isAutomatic() && tr->transitionEndTrack() == m_dragItemInfo.track) { - ItemInfo trInfo = tr->info(); - ItemInfo newTrInfo = trInfo; - newTrInfo.startPos = dragItem->startPos(); - newTrInfo.cropDuration = newTrInfo.endPos - dragItem->startPos(); - ClipItem *upperClip = m_view->getClipItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track - 1); - if (!upperClip /*|| !upperClip->baseClip()->isTransparent()*/) { - if (!m_view->getClipItemAtEnd(newTrInfo.endPos, tr->track())) { - // transition end should be adjusted to clip on upper track - newTrInfo.endPos = newTrInfo.endPos + (newTrInfo.startPos - trInfo.startPos); - } - if (newTrInfo.startPos < newTrInfo.endPos) { - m_view->adjustTimelineTransitions(m_view->sceneEditMode(), tr, moveCommand); - QDomElement old = tr->toXML(); - if (tr->updateKeyframes(trInfo, newTrInfo)) { - QDomElement xml = old.cloneNode().toElement(); - m_transitionHandler->updateTransition(xml.attribute(QStringLiteral("tag")), xml.attribute(QStringLiteral("tag")), - xml.attribute(QStringLiteral("transition_btrack")).toInt(), - xml.attribute(QStringLiteral("transition_atrack")).toInt(), newTrInfo.startPos, - newTrInfo.endPos, xml); - new EditTransitionCommand(m_view, tr->track(), tr->startPos(), old, xml, false, moveCommand); - } - new MoveTransitionCommand(m_view, trInfo, newTrInfo, true, false, moveCommand); - } - } - } - if (m_dragItemInfo.track == info.track && (tr == nullptr || tr->endPos() < m_dragItemInfo.endPos)) { - // Check if there is a transition at clip end - tr = m_view->getTransitionItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track + 1); - if ((tr != nullptr) && tr->isAutomatic() && tr->transitionEndTrack() == m_dragItemInfo.track) { - ItemInfo trInfo = tr->info(); - ItemInfo newTrInfo = trInfo; - newTrInfo.endPos = dragItem->endPos(); - ClipItem *upperClip = m_view->getClipItemAtStart(m_dragItemInfo.startPos, m_dragItemInfo.track + 1); - if (!upperClip /*|| !upperClip->baseClip()->isTransparent()*/) { - if (m_view->getClipItemAtStart(trInfo.startPos, tr->track()) == nullptr) { - // transition moved, update start - newTrInfo.startPos = dragItem->endPos() - newTrInfo.cropDuration; - } else { - // transition start should be resized - newTrInfo.cropDuration = dragItem->endPos() - newTrInfo.startPos; - } - if (newTrInfo.startPos < newTrInfo.endPos) { - m_view->adjustTimelineTransitions(m_view->sceneEditMode(), tr, moveCommand); - if (tr->updateKeyframes(trInfo, newTrInfo)) { - QDomElement old = tr->toXML(); - QDomElement xml = old.cloneNode().toElement(); - m_transitionHandler->updateTransition(xml.attribute(QStringLiteral("tag")), xml.attribute(QStringLiteral("tag")), - xml.attribute(QStringLiteral("transition_btrack")).toInt(), - xml.attribute(QStringLiteral("transition_atrack")).toInt(), newTrInfo.startPos, - newTrInfo.endPos, xml); - new EditTransitionCommand(m_view, tr->track(), tr->startPos(), old, xml, false, moveCommand); - } - new MoveTransitionCommand(m_view, trInfo, newTrInfo, true, false, moveCommand); - } - } - } - } - m_view->updateTrackDuration(info.track, moveCommand); - if (m_dragItemInfo.track != info.track) { - m_view->updateTrackDuration(m_dragItemInfo.track, moveCommand); - } - bool refresh = item->hasVisibleVideo(); - if (refresh) { - new RefreshMonitorCommand(m_view, QList() << info << m_dragItemInfo, false, false, moveCommand); - } - m_commandStack->push(moveCommand); - if (refresh) { - m_view->monitorRefresh(QList() << info << m_dragItemInfo, true); - } - item = m_view->getClipItemAtStart(info.startPos, info.track, info.endPos); - if (item) { - item->setItemLocked(isLocked); - item->setSelected(true); - } - } else { - // undo last move and emit error message - bool snap = KdenliveSettings::snaptopoints(); - KdenliveSettings::setSnaptopoints(false); - item->setPos((int)m_dragItemInfo.startPos.frames(m_view->fps()), m_view->getPositionFromTrack(m_dragItemInfo.track) + 1); - KdenliveSettings::setSnaptopoints(snap); - m_view->displayMessage(i18n("Cannot move clip to position %1", m_view->timecode().getTimecodeFromFrames(info.startPos.frames(m_view->fps()))), - ErrorMessage); - } - } else if (dragItem->type() == TransitionWidget && (m_dragItemInfo.startPos != info.startPos || m_dragItemInfo.track != info.track)) { - Transition *transition = static_cast(dragItem); - transition->updateTransitionEndTrack(m_view->getPreviousVideoTrack(dragItem->track())); - if (!m_transitionHandler->moveTransition(transition->transitionTag(), m_dragItemInfo.track, dragItem->track(), transition->transitionEndTrack(), - m_dragItemInfo.startPos, m_dragItemInfo.endPos, info.startPos, info.endPos)) { - // Moving transition failed, revert to previous position - m_view->displayMessage(i18n("Cannot move transition"), ErrorMessage); - transition->setPos((int)m_dragItemInfo.startPos.frames(m_view->fps()), m_view->getPositionFromTrack(m_dragItemInfo.track) + 1); - } else { - auto *moveCommand = new QUndoCommand(); - moveCommand->setText(i18n("Move transition")); - m_view->adjustTimelineTransitions(m_view->sceneEditMode(), transition, moveCommand); - new MoveTransitionCommand(m_view, m_dragItemInfo, info, false, true, moveCommand); - m_view->updateTrackDuration(info.track, moveCommand); - if (m_dragItemInfo.track != info.track) { - m_view->updateTrackDuration(m_dragItemInfo.track, moveCommand); - } - m_commandStack->push(moveCommand); - m_view->monitorRefresh(QList() << info << m_dragItemInfo, true); - m_view->updateTransitionWidget(transition, info); - } - } - } else { - // Moving several clips. We need to delete them and readd them to new position, - // or they might overlap each other during the move - AbstractGroupItem *group = m_view->selectionGroup(); - ItemInfo cutInfo; - cutInfo.startPos = GenTime(dragItem->scenePos().x(), m_view->fps()); - cutInfo.cropDuration = group->duration(); - cutInfo.endPos = cutInfo.startPos + cutInfo.cropDuration; - - QList items = group->childItems(); - QList clipsToMove; - QList transitionsToMove; - - GenTime timeOffset = GenTime(dragItem->scenePos().x(), m_view->fps()) - m_dragItemInfo.startPos; - const int trackOffset = m_view->getTrackFromPos(dragItem->scenePos().y()) - m_dragItemInfo.track; - - auto *moveGroup = new QUndoCommand(); - moveGroup->setText(i18n("Move group")); - - // Expand groups - int max = items.count(); - for (int i = 0; i < max; ++i) { - if (items.at(i)->type() == GroupWidget) { - items += items.at(i)->childItems(); - } - } - QList updatedClipsToMove; - QList updatedTransitionsToMove; - for (int i = 0; i < items.count(); ++i) { - if (items.at(i)->type() != AVWidget && items.at(i)->type() != TransitionWidget) { - continue; - } - AbstractClipItem *item = static_cast(items.at(i)); - if (item->type() == AVWidget) { - clipsToMove.append(item->info()); - updatedClipsToMove << item->info(); - } else { - transitionsToMove.append(item->info()); - updatedTransitionsToMove << item->info(); - } - } - if (m_view->sceneEditMode() == TimelineMode::InsertEdit) { - m_view->cutTimeline(cutInfo.startPos.frames(m_view->fps()), clipsToMove, transitionsToMove, moveGroup, -1); - new AddSpaceCommand(m_view, cutInfo, clipsToMove, true, moveGroup, false); - bool isLastClip = m_view->isLastClip(cutInfo); - if (!isLastClip && cutInfo.track == m_dragItemInfo.track && cutInfo.startPos < m_dragItemInfo.startPos) { - // TODO: remove offset to allow finding correct clip to move - // initialClip.startPos += m_dragItemInfo.cropDuration; - // initialClip.endPos += m_dragItemInfo.cropDuration; - } - } else if (m_view->sceneEditMode() == TimelineMode::OverwriteEdit) { - m_view->extractZone(QPoint(cutInfo.startPos.frames(m_view->fps()), cutInfo.endPos.frames(m_view->fps())), false, updatedClipsToMove, moveGroup, -1); - } - new MoveGroupCommand(m_view, clipsToMove, transitionsToMove, timeOffset, trackOffset, true, true, moveGroup); - m_commandStack->push(moveGroup); - } - m_dragItemInfo = ItemInfo(); - m_view->setOperationMode(None); -} - -void MoveManager::slotCheckMouseScrolling() -{ - if (m_scrollOffset == 0) { - m_scrollTimer.stop(); - return; - } - m_view->horizontalScrollBar()->setValue(m_view->horizontalScrollBar()->value() + m_scrollOffset); - m_scrollTimer.start(); -} diff --git a/src/timeline/managers/movemanager.h b/src/timeline/managers/movemanager.h deleted file mode 100644 index 32c0f2b31..000000000 --- a/src/timeline/managers/movemanager.h +++ /dev/null @@ -1,58 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef MOVEMANAGER_H -#define MOVEMANAGER_H - -#include "abstracttoolmanager.h" - -#include -#include - -class TransitionHandler; - -/** - * @namespace MoveManager - * @brief Provides convenience methods to handle selection tool. - */ - -class MoveManager : public AbstractToolManager -{ - Q_OBJECT - -public: - explicit MoveManager(TransitionHandler *handler, CustomTrackView *view, std::shared_ptr commandStack); - bool mousePress(QMouseEvent *event, const ItemInfo &info = ItemInfo(), const QList &list = QList()) override; - void mouseRelease(QMouseEvent *event, GenTime pos = GenTime()) override; - bool mouseMove(QMouseEvent *event, int pos, int) override; - -private: - ItemInfo m_dragItemInfo; - TransitionHandler *m_transitionHandler; - int m_scrollOffset; - int m_scrollTrigger; - QTimer m_scrollTimer; - bool m_dragMoved; - QPoint m_clickPoint; - -private slots: - void slotCheckMouseScrolling(); -}; - -#endif diff --git a/src/timeline/managers/previewmanager.cpp b/src/timeline/managers/previewmanager.cpp deleted file mode 100644 index 5c2d1042c..000000000 --- a/src/timeline/managers/previewmanager.cpp +++ /dev/null @@ -1,667 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "previewmanager.h" -#include "doc/docundostack.hpp" -#include "doc/kdenlivedoc.h" -#include "timeline2/view/timelinecontroller.h" -#include "core.h" -#include "monitor/monitor.h" -#include "kdenlivesettings.h" - -#include -#include -#include -#include - -PreviewManager::PreviewManager(TimelineController *controller, Mlt::Tractor *tractor) - : QObject() - , workingPreview(-1) - , m_controller(controller) - , m_tractor(tractor) - , m_previewTrack(nullptr) - , m_overlayTrack(nullptr) - , m_initialized(false) - , m_abortPreview(false) - , m_previewTrackIndex(-1) -{ - m_previewGatherTimer.setSingleShot(true); - m_previewGatherTimer.setInterval(200); -} - -PreviewManager::~PreviewManager() -{ - if (m_initialized) { - abortRendering(); - if (m_undoDir.dirName() == QLatin1String("undo")) { - m_undoDir.removeRecursively(); - } - if ((pCore->currentDoc()->url().isEmpty() && m_cacheDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot).isEmpty()) || - m_cacheDir.entryList(QDir::AllEntries | QDir::NoDotAndDotDot).isEmpty()) { - if (m_cacheDir.dirName() == QLatin1String("preview")) { - m_cacheDir.removeRecursively(); - } - } - } - delete m_previewTrack; -} - -bool PreviewManager::initialize() -{ - // Make sure our document id does not contain .. tricks - bool ok; - KdenliveDoc *doc = pCore->currentDoc(); - QString documentId = QDir::cleanPath(doc->getDocumentProperty(QStringLiteral("documentid"))); - documentId.toLongLong(&ok, 10); - if (!ok || documentId.isEmpty()) { - // Something is wrong, documentId should be a number (ms since epoch), abort - pCore->displayMessage(i18n("Wrong document ID, cannot create temporary folder"), ErrorMessage); - return false; - } - m_cacheDir = doc->getCacheDir(CachePreview, &ok); - if (!m_cacheDir.exists() || !ok) { - pCore->displayMessage(i18n("Cannot create folder %1", m_cacheDir.absolutePath()), ErrorMessage); - return false; - } - if (m_cacheDir.dirName() != QLatin1String("preview") || m_cacheDir == QDir() || - (!m_cacheDir.exists(QStringLiteral("undo")) && !m_cacheDir.mkdir(QStringLiteral("undo"))) || !m_cacheDir.absolutePath().contains(documentId)) { - pCore->displayMessage(i18n("Something is wrong with cache folder %1", m_cacheDir.absolutePath()), ErrorMessage); - return false; - } - if (!loadParams()) { - pCore->displayMessage(i18n("Invalid timeline preview parameters"), ErrorMessage); - return false; - } - m_undoDir = QDir(m_cacheDir.absoluteFilePath(QStringLiteral("undo"))); - - // Make sure our cache dirs are inside the temporary folder - if (!m_cacheDir.makeAbsolute() || !m_undoDir.makeAbsolute() || !m_undoDir.mkpath(QStringLiteral("."))) { - pCore->displayMessage(i18n("Something is wrong with cache folders"), ErrorMessage); - return false; - } - - connect(this, &PreviewManager::cleanupOldPreviews, this, &PreviewManager::doCleanupOldPreviews); - connect(doc, &KdenliveDoc::removeInvalidUndo, this, &PreviewManager::slotRemoveInvalidUndo, Qt::DirectConnection); - m_previewTimer.setSingleShot(true); - m_previewTimer.setInterval(3000); - connect(&m_previewTimer, &QTimer::timeout, this, &PreviewManager::startPreviewRender); - connect(this, &PreviewManager::previewRender, this, &PreviewManager::gotPreviewRender); - connect(&m_previewGatherTimer, &QTimer::timeout, this, &PreviewManager::slotProcessDirtyChunks); - m_initialized = true; - return true; -} - -bool PreviewManager::buildPreviewTrack() -{ - if (m_previewTrack) { - return false; - } - // Create overlay track - qDebug()<<"/// BUILDING PREVIEW TRACK\n----------------------\n----------------__"; - m_previewTrack = new Mlt::Playlist(*m_tractor->profile()); - m_tractor->lock(); - reconnectTrack(); - m_tractor->unlock(); - return true; -} - -void PreviewManager::loadChunks(QVariantList previewChunks, QVariantList dirtyChunks, const QDateTime &documentDate) -{ - if (previewChunks.isEmpty()) { - previewChunks = m_renderedChunks; - } - if (dirtyChunks.isEmpty()) { - dirtyChunks = m_dirtyChunks; - } - for (const auto &frame : previewChunks) { - const QString fileName = m_cacheDir.absoluteFilePath(QStringLiteral("%1.%2").arg(frame.toInt()).arg(m_extension)); - QFile file(fileName); - if (file.exists()) { - if (!documentDate.isNull() && QFileInfo(file).lastModified() > documentDate) { - // Timeline preview file was created after document, invalidate - file.remove(); - dirtyChunks << frame; - } else { - gotPreviewRender(frame.toInt(), fileName, 1000); - } - } else { - dirtyChunks << frame; - } - } - if (!previewChunks.isEmpty()) { - m_controller->renderedChunksChanged(); - } - if (!dirtyChunks.isEmpty()) { - for (const auto &i : dirtyChunks) { - if (!m_dirtyChunks.contains(i)) { - m_dirtyChunks << i; - } - } - m_controller->dirtyChunksChanged(); - } -} - -void PreviewManager::deletePreviewTrack() -{ - m_tractor->lock(); - disconnectTrack(); - delete m_previewTrack; - m_previewTrack = nullptr; - m_dirtyChunks.clear(); - m_renderedChunks.clear(); - m_controller->dirtyChunksChanged(); - m_controller->renderedChunksChanged(); - m_tractor->unlock(); -} - -const QDir PreviewManager::getCacheDir() const -{ - return m_cacheDir; -} - -void PreviewManager::reconnectTrack() -{ - disconnectTrack(); - if (!m_previewTrack && !m_overlayTrack) { - m_previewTrackIndex = -1; - return; - } - m_previewTrackIndex = m_tractor->count(); - int increment = 0; - if (m_previewTrack) { - m_tractor->insert_track(*m_previewTrack, m_previewTrackIndex); - std::shared_ptrtk(m_tractor->track(m_previewTrackIndex)); - tk->set("hide", 2); - tk->set("id", "timeline_preview"); - increment++; - } - if (m_overlayTrack) { - m_tractor->insert_track(*m_overlayTrack, m_previewTrackIndex + increment); - std::shared_ptrtk(m_tractor->track(m_previewTrackIndex + increment)); - tk->set("hide", 2); - tk->set("id", "timeline_overlay"); - } -} - -void PreviewManager::disconnectTrack() -{ - if (m_previewTrackIndex > -1) { - Mlt::Producer *prod = m_tractor->track(m_previewTrackIndex); - if (strcmp(prod->get("id"), "timeline_preview") == 0 || strcmp(prod->get("id"), "timeline_overlay") == 0) { - m_tractor->remove_track(m_previewTrackIndex); - } - delete prod; - if (m_tractor->count() == m_previewTrackIndex + 1) { - // overlay track still here, remove - Mlt::Producer *prod = m_tractor->track(m_previewTrackIndex); - if (strcmp(prod->get("id"), "timeline_overlay") == 0) { - m_tractor->remove_track(m_previewTrackIndex); - } - delete prod; - } - } - qDebug()<<"// DISCONNECTING PREV TK............."; - m_previewTrackIndex = -1; -} - -bool PreviewManager::loadParams() -{ - KdenliveDoc *doc = pCore->currentDoc(); - m_extension = doc->getDocumentProperty(QStringLiteral("previewextension")); - m_consumerParams = doc->getDocumentProperty(QStringLiteral("previewparameters")).split(QLatin1Char(' '), QString::SkipEmptyParts); - - if (m_consumerParams.isEmpty() || m_extension.isEmpty()) { - doc->selectPreviewProfile(); - m_consumerParams = doc->getDocumentProperty(QStringLiteral("previewparameters")).split(QLatin1Char(' '), QString::SkipEmptyParts); - m_extension = doc->getDocumentProperty(QStringLiteral("previewextension")); - } - if (m_consumerParams.isEmpty() || m_extension.isEmpty()) { - return false; - } - // Remove the r= and s= parameter (forcing framerate / frame size) as it causes rendering failure. - // These parameters should be provided by MLT's profile - for (int i = 0; i < m_consumerParams.count(); i++) { - if (m_consumerParams.at(i).startsWith(QStringLiteral("r=")) || m_consumerParams.at(i).startsWith(QStringLiteral("s="))) { - m_consumerParams.removeAt(i); - i--; - } - } - m_consumerParams << QStringLiteral("an=1"); - if (KdenliveSettings::gpu_accel()) { - m_consumerParams << QStringLiteral("glsl.=1"); - } - return true; -} - -void PreviewManager::invalidatePreviews(const QVariantList &chunks) -{ - QMutexLocker lock(&m_previewMutex); - bool timer = false; - if (m_previewTimer.isActive()) { - m_previewTimer.stop(); - timer = true; - } - KdenliveDoc *doc = pCore->currentDoc(); - int stackIx = doc->commandStack()->index(); - int stackMax = doc->commandStack()->count(); - if (stackIx == stackMax && !m_undoDir.exists(QString::number(stackIx - 1))) { - // We just added a new command in stack, archive existing chunks - int ix = stackIx - 1; - m_undoDir.mkdir(QString::number(ix)); - bool foundPreviews = false; - for (const auto &i : chunks) { - QString current = QStringLiteral("%1.%2").arg(i.toInt()).arg(m_extension); - if (m_cacheDir.rename(current, QStringLiteral("undo/%1/%2").arg(ix).arg(current))) { - foundPreviews = true; - } - } - if (!foundPreviews) { - // No preview files found, remove undo folder - m_undoDir.rmdir(QString::number(ix)); - } else { - // new chunks archived, cleanup old ones - emit cleanupOldPreviews(); - } - } else { - // Restore existing chunks, delete others - // Check if we just undo the last stack action, then backup, otherwise delete - bool lastUndo = false; - if (stackIx == stackMax - 1) { - if (!m_undoDir.exists(QString::number(stackMax))) { - lastUndo = true; - bool foundPreviews = false; - m_undoDir.mkdir(QString::number(stackMax)); - for (const auto &i : chunks) { - QString current = QStringLiteral("%1.%2").arg(i.toInt()).arg(m_extension); - if (m_cacheDir.rename(current, QStringLiteral("undo/%1/%2").arg(stackMax).arg(current))) { - foundPreviews = true; - } - } - if (!foundPreviews) { - m_undoDir.rmdir(QString::number(stackMax)); - } - } - } - bool moveFile = true; - QDir tmpDir = m_undoDir; - if (!tmpDir.cd(QString::number(stackIx))) { - moveFile = false; - } - QVariantList foundChunks; - for (const auto &i : chunks) { - QString cacheFileName = QStringLiteral("%1.%2").arg(i.toInt()).arg(m_extension); - if (!lastUndo) { - m_cacheDir.remove(cacheFileName); - } - if (moveFile) { - if (QFile::copy(tmpDir.absoluteFilePath(cacheFileName), m_cacheDir.absoluteFilePath(cacheFileName))) { - foundChunks << i; - } - } - } - qSort(foundChunks); - reloadChunks(foundChunks); - } - doc->setModified(true); - if (timer) { - m_previewTimer.start(); - } -} - -void PreviewManager::doCleanupOldPreviews() -{ - if (m_undoDir.dirName() != QLatin1String("undo")) { - return; - } - QStringList dirs = m_undoDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - - // Use QCollator to do a natural sorting so that 10 is after 2 - QCollator collator; - collator.setNumericMode(true); - std::sort(dirs.begin(), dirs.end(), [&collator](const QString &file1, const QString &file2) { return collator.compare(file1, file2) < 0; }); - bool ok; - while (dirs.count() > 5) { - QDir tmp = m_undoDir; - QString dirName = dirs.takeFirst(); - dirName.toInt(&ok); - if (ok && tmp.cd(dirName)) { - tmp.removeRecursively(); - } - } -} - -void PreviewManager::clearPreviewRange() -{ - m_previewGatherTimer.stop(); - abortPreview(); - m_tractor->lock(); - bool hasPreview = m_previewTrack != nullptr; - for (const auto &ix : m_renderedChunks) { - m_cacheDir.remove(QStringLiteral("%1.%2").arg(ix.toInt()).arg(m_extension)); - if (!hasPreview) { - continue; - } - int trackIx = m_previewTrack->get_clip_index_at(ix.toInt()); - if (!m_previewTrack->is_blank(trackIx)) { - Mlt::Producer *prod = m_previewTrack->replace_with_blank(trackIx); - delete prod; - } - } - if (hasPreview) { - m_previewTrack->consolidate_blanks(); - } - m_tractor->unlock(); - m_renderedChunks.clear(); - m_controller->renderedChunksChanged(); -} - -void PreviewManager::addPreviewRange(const QPoint zone, bool add) -{ - int chunkSize = KdenliveSettings::timelinechunks(); - int startChunk = zone.x() / chunkSize; - int endChunk = rintl(zone.y() / chunkSize); - QList toRemove; - qDebug()<<" // / RESUQEST CHUNKS; "<dirtyChunksChanged(); - if (!m_previewThread.isRunning() && KdenliveSettings::autopreview()) { - m_previewTimer.start(); - } - } else { - // Remove processed chunks - bool isRendering = m_previewThread.isRunning(); - m_previewGatherTimer.stop(); - abortPreview(); - m_tractor->lock(); - bool hasPreview = m_previewTrack != nullptr; - for (int ix : toRemove) { - m_cacheDir.remove(QStringLiteral("%1.%2").arg(ix).arg(m_extension)); - if (!hasPreview) { - continue; - } - int trackIx = m_previewTrack->get_clip_index_at(ix); - if (!m_previewTrack->is_blank(trackIx)) { - Mlt::Producer *prod = m_previewTrack->replace_with_blank(trackIx); - delete prod; - } - } - if (hasPreview) { - m_previewTrack->consolidate_blanks(); - } - m_tractor->unlock(); - if (isRendering || KdenliveSettings::autopreview()) { - m_previewTimer.start(); - } - } -} - -void PreviewManager::abortRendering() -{ - if (!m_previewThread.isRunning()) { - return; - } - m_abortPreview = true; - emit abortPreview(); - m_previewThread.waitForFinished(); - // Re-init time estimation - emit previewRender(0, QString(), 0); -} - -void PreviewManager::startPreviewRender() -{ - if (m_renderedChunks.isEmpty() && m_dirtyChunks.isEmpty()) { - m_controller->addPreviewRange(true); - } - if (!m_dirtyChunks.isEmpty()) { - // Abort any rendering - abortRendering(); - m_waitingThumbs.clear(); - const QString sceneList = QStringLiteral("xml:") + m_cacheDir.absoluteFilePath(QStringLiteral("preview.mlt")); - pCore->getMonitor(Kdenlive::ProjectMonitor)->sceneList(m_cacheDir.absolutePath(), sceneList); - //pCore->currentDoc()->saveMltPlaylist(sceneList); - m_previewThread = QtConcurrent::run(this, &PreviewManager::doPreviewRender, sceneList); - } -} - -void PreviewManager::doPreviewRender(const QString &scene) -{ - int progress; - int chunkSize = KdenliveSettings::timelinechunks(); - // initialize progress bar - emit previewRender(0, QString(), 0); - int ct = 0; - qSort(m_dirtyChunks); - while (!m_dirtyChunks.isEmpty()) { - workingPreview = m_dirtyChunks.takeFirst().toInt(); - m_controller->workingPreviewChanged(); - ct++; - QString fileName = QStringLiteral("%1.%2").arg(workingPreview).arg(m_extension); - if (m_dirtyChunks.isEmpty()) { - progress = 1000; - } else { - progress = (double)(ct) / (ct + m_dirtyChunks.count()) * 1000; - } - if (m_cacheDir.exists(fileName)) { - // This chunk already exists - emit previewRender(workingPreview, m_cacheDir.absoluteFilePath(fileName), progress); - continue; - } - // Build rendering process - QStringList args; - args << scene; - args << QStringLiteral("in=") + QString::number(workingPreview); - args << QStringLiteral("out=") + QString::number(workingPreview + chunkSize - 1); - args << QStringLiteral("-consumer") << QStringLiteral("avformat:") + m_cacheDir.absoluteFilePath(fileName); - args << m_consumerParams; - QProcess previewProcess; - connect(this, &PreviewManager::abortPreview, &previewProcess, &QProcess::kill, Qt::DirectConnection); - previewProcess.start(KdenliveSettings::rendererpath(), args); - if (previewProcess.waitForStarted()) { - previewProcess.waitForFinished(-1); - if (previewProcess.exitStatus() != QProcess::NormalExit || previewProcess.exitCode() != 0) { - // Something went wrong - if (m_abortPreview) { - emit previewRender(0, QString(), 1000); - } else { - emit previewRender(workingPreview, previewProcess.readAllStandardError(), -1); - } - QFile::remove(m_cacheDir.absoluteFilePath(fileName)); - break; - } else { - emit previewRender(workingPreview, m_cacheDir.absoluteFilePath(fileName), progress); - } - } else { - emit previewRender(workingPreview, QString(), -1); - break; - } - } - // QFile::remove(scene); - workingPreview = -1; - m_controller->workingPreviewChanged(); - m_abortPreview = false; -} - -void PreviewManager::slotProcessDirtyChunks() -{ - if (m_dirtyChunks.isEmpty()) { - return; - } - invalidatePreviews(m_dirtyChunks); - if (KdenliveSettings::autopreview()) { - m_previewTimer.start(); - } -} - -void PreviewManager::slotRemoveInvalidUndo(int ix) -{ - QMutexLocker lock(&m_previewMutex); - if (m_undoDir.dirName() != QLatin1String("undo")) { - // Make sure we delete correct folder - return; - } - QStringList dirs = m_undoDir.entryList(QDir::Dirs | QDir::NoDotAndDotDot); - bool ok; - for (const QString &dir : dirs) { - if (dir.toInt(&ok) >= ix && ok) { - QDir tmp = m_undoDir; - if (tmp.cd(dir)) { - tmp.removeRecursively(); - } - } - } -} - -void PreviewManager::invalidatePreview(int startFrame, int endFrame) -{ - int chunkSize = KdenliveSettings::timelinechunks(); - int start = startFrame / chunkSize; - int end = lrintf(endFrame / chunkSize); - start *= chunkSize; - end *= chunkSize; - - qSort(m_renderedChunks); - for (const auto &ix : m_renderedChunks) { - if (ix.toInt() >= start && ix.toInt() <= end) { - return; - } - } - m_previewGatherTimer.stop(); - abortPreview(); - m_tractor->lock(); - bool hasPreview = m_previewTrack != nullptr; - for (int i = start; i <= end; i += chunkSize) { - if (m_renderedChunks.contains(i) && hasPreview) { - int ix = m_previewTrack->get_clip_index_at(i); - if (m_previewTrack->is_blank(ix)) { - continue; - } - Mlt::Producer *prod = m_previewTrack->replace_with_blank(ix); - delete prod; - } - } - if (hasPreview) { - m_previewTrack->consolidate_blanks(); - } - m_tractor->unlock(); - m_previewGatherTimer.start(); -} - -void PreviewManager::reloadChunks(const QVariantList chunks) -{ - if (m_previewTrack == nullptr || chunks.isEmpty()) { - return; - } - m_tractor->lock(); - for (const auto &ix : chunks) { - if (m_previewTrack->is_blank_at(ix.toInt())) { - const QString fileName = m_cacheDir.absoluteFilePath(QStringLiteral("%1.%2").arg(ix.toInt()).arg(m_extension)); - Mlt::Producer prod(*m_tractor->profile(), nullptr, fileName.toUtf8().constData()); - if (prod.is_valid()) { - //m_ruler->updatePreview(ix, true); - prod.set("mlt_service", "avformat-novalidate"); - m_previewTrack->insert_at(ix.toInt(), &prod, 1); - } - } - } - m_previewTrack->consolidate_blanks(); - m_tractor->unlock(); -} - -void PreviewManager::gotPreviewRender(int frame, const QString &file, int progress) -{ - qDebug()<<"// GOT PREV RENDER: "<currentDoc()->previewProgress(progress); - if (progress < 0) { - pCore->displayMessage(i18n("Preview rendering failed, check your parameters. %1Show details...%2", - QString("")), - QStringLiteral("")), - MltError); - } - return; - } - m_tractor->lock(); - if (m_previewTrack->is_blank_at(frame)) { - Mlt::Producer prod(*m_tractor->profile(), file.toUtf8().constData()); - if (prod.is_valid()) { - qDebug()<<"// YOP PROD OK"; - m_renderedChunks << frame; - m_controller->renderedChunksChanged(); - //m_ruler->updatePreview(frame, true, true); - prod.set("mlt_service", "avformat-novalidate"); - m_previewTrack->insert_at(frame, &prod, 1); - } else { - qDebug()<<"// INVALID PROD: "<consolidate_blanks(); - m_tractor->unlock(); - pCore->currentDoc()->previewProgress(progress); - pCore->currentDoc()->setModified(true); -} - -int PreviewManager::setOverlayTrack(Mlt::Playlist *overlay) -{ - m_overlayTrack = overlay; - reconnectTrack(); - return m_previewTrackIndex; -} - -void PreviewManager::removeOverlayTrack() -{ - delete m_overlayTrack; - m_overlayTrack = nullptr; - reconnectTrack(); -} - -QPair PreviewManager::previewChunks() const -{ - QStringList renderedChunks; - QStringList dirtyChunks; - for (const QVariant &frame : m_renderedChunks) { - renderedChunks << frame.toString(); - } - for (const QVariant &frame : m_dirtyChunks) { - dirtyChunks << frame.toString(); - } - return {renderedChunks, dirtyChunks}; -} - diff --git a/src/timeline/managers/previewmanager.h b/src/timeline/managers/previewmanager.h deleted file mode 100644 index 5df7a104e..000000000 --- a/src/timeline/managers/previewmanager.h +++ /dev/null @@ -1,143 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef PREVIEWMANAGER_H -#define PREVIEWMANAGER_H - -#include "definitions.h" - -#include -#include -#include -#include - -class TimelineController; - -namespace Mlt { -class Tractor; -class Playlist; -} - -/** - * @namespace PreviewManager - * @brief Handles timeline preview. - * This manager creates an additional video track on top of the current timeline and renders - * chunks (small video files of 25 frames) that are added on this track when rendrerd. - * This allow us to get a preview with a smooth playback of our project. - * Only the preview zone is rendered. Once defined, a preview zone shows as a red line below - * the timeline ruler. As chunks are rendered, the zone turns to green. - */ - -class PreviewManager : public QObject -{ - Q_OBJECT - -public: - friend class TimelineController; - - explicit PreviewManager(TimelineController *controller, Mlt::Tractor *tractor); - virtual ~PreviewManager(); - /** @brief: initialize base variables, return false if error. */ - bool initialize(); - /** @brief: a timeline operation caused changes to frames between startFrame and endFrame. */ - void invalidatePreview(int startFrame, int endFrame); - /** @brief: after a small delay (some operations trigger several invalidatePreview calls), take care of these invalidated chunks. */ - void invalidatePreviews(const QVariantList &chunks); - /** @brief: user adds current timeline zone to the preview zone. */ - void addPreviewRange(const QPoint zone, bool add); - /** @brief: Remove all existing previews. */ - void clearPreviewRange(); - /** @brief: stops current rendering process. */ - void abortRendering(); - /** @brief: rendering parameters have changed, reload them. */ - bool loadParams(); - /** @brief: Create the preview track if not existing. */ - bool buildPreviewTrack(); - /** @brief: Delete the preview track. */ - void deletePreviewTrack(); - /** @brief: Whenever we save or render our project, we remove the preview track so it is not saved. */ - void reconnectTrack(); - /** @brief: After project save or render, re-add our preview track. */ - void disconnectTrack(); - /** @brief: Returns directory currently used to store the preview files. */ - const QDir getCacheDir() const; - /** @brief: Load existing ruler chunks. */ - void loadChunks(QVariantList previewChunks, QVariantList dirtyChunks, const QDateTime &documentDate); - int setOverlayTrack(Mlt::Playlist *overlay); - /** @brief Remove the effect compare overlay track */ - void removeOverlayTrack(); - /** @brief The current preview chunk being processed, -1 if none */ - int workingPreview; - /** @brief Returns the list of existing chunks */ - QPair previewChunks() const; - bool hasOverlayTrack() const; - bool hasPreviewTrack() const; - int addedTracks() const; - -private: - TimelineController *m_controller; - Mlt::Tractor *m_tractor; - Mlt::Playlist *m_previewTrack; - Mlt::Playlist *m_overlayTrack; - int m_previewTrackIndex; - /** @brief: The directory used to store the preview files. */ - QDir m_cacheDir; - /** @brief: The directory used to store undo history of preview files (child of m_cacheDir). */ - QDir m_undoDir; - QMutex m_previewMutex; - QStringList m_consumerParams; - QString m_extension; - /** @brief: Timer used to autostart preview rendering. */ - QTimer m_previewTimer; - /** @brief: Since some timeline operations generate several invalidate calls, use a timer to get them all. */ - QTimer m_previewGatherTimer; - bool m_initialized; - bool m_abortPreview; - QList m_waitingThumbs; - QFuture m_previewThread; - /** @brief: After an undo/redo, if we have preview history, use it. */ - void reloadChunks(const QVariantList chunks); - -private slots: - /** @brief: To avoid filling the hard drive, remove preview undo history after 5 steps. */ - void doCleanupOldPreviews(); - /** @brief: Start the real rendering process. */ - void doPreviewRender(const QString &scene); - /** @brief: If user does an undo, then makes a new timeline operation, delete undo history of more recent stack . */ - void slotRemoveInvalidUndo(int ix); - /** @brief: When the timer collecting invalid zones is done, process. */ - void slotProcessDirtyChunks(); - -public slots: - /** @brief: Prepare and start rendering. */ - void startPreviewRender(); - /** @brief: A chunk has been created, notify ruler. */ - void gotPreviewRender(int frame, const QString &file, int progress); - -protected: - QVariantList m_renderedChunks; - QVariantList m_dirtyChunks; - -signals: - void abortPreview(); - void cleanupOldPreviews(); - void previewRender(int frame, const QString &file, int progress); -}; - -#endif diff --git a/src/timeline/managers/razormanager.cpp b/src/timeline/managers/razormanager.cpp deleted file mode 100644 index ca4bfa8d2..000000000 --- a/src/timeline/managers/razormanager.cpp +++ /dev/null @@ -1,144 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "razormanager.h" -#include "../clipitem.h" -#include "doc/docundostack.hpp" -#include "timeline/abstractgroupitem.h" -#include "timeline/clipitem.h" -#include "timeline/customtrackview.h" -#include "timeline/timelinecommands.h" -#include "utils/KoIconUtils.h" - -#include -#include -#include -#include -#include - -RazorManager::RazorManager(CustomTrackView *view, std::shared_ptr commandStack) - : AbstractToolManager(RazorType, view, commandStack) - , m_cutLine(nullptr) -{ - QIcon razorIcon = KoIconUtils::themedIcon(QStringLiteral("edit-cut")); - m_cursor = QCursor(razorIcon.pixmap(32, 32)); -} - -bool RazorManager::mousePress(QMouseEvent *, const ItemInfo &info, const QList &) -{ - AbstractClipItem *dragItem = m_view->dragItem(); - if (!dragItem) { - return false; - } - QList items; - if (dragItem->parentItem()) { - items << dragItem->parentItem()->childItems(); - } else { - items << dragItem; - } - m_view->cutSelectedClips(items, info.startPos); - return true; -} - -void RazorManager::enterEvent(int, double trackHeight) -{ - buildCutLine(trackHeight); -} - -void RazorManager::initTool(double trackHeight) -{ - buildCutLine(trackHeight); - m_view->setCursor(m_cursor); -} - -void RazorManager::buildCutLine(double trackHeight) -{ - if (!m_cutLine) { - m_cutLine = m_view->scene()->addLine(0, 0, 0, trackHeight); - m_cutLine->setZValue(1000); - QPen pen1 = QPen(); - pen1.setWidth(1); - QColor line(Qt::red); - pen1.setColor(line); - m_cutLine->setPen(pen1); - m_cutLine->setFlag(QGraphicsItem::ItemIgnoresTransformations, true); - slotRefreshCutLine(); - } -} - -void RazorManager::leaveEvent() -{ - delete m_cutLine; - m_cutLine = nullptr; -} - -void RazorManager::closeTool() -{ - delete m_cutLine; - m_cutLine = nullptr; -} - -bool RazorManager::mouseMove(QMouseEvent *, int pos, int track) -{ - if (m_cutLine) { - m_cutLine->setPos(pos, track); - } - return true; -} - -void RazorManager::updateTimelineItems() -{ - if (m_cutLine) { - slotRefreshCutLine(); - } -} - -void RazorManager::mouseRelease(QMouseEvent *, GenTime pos) -{ - Q_UNUSED(pos); - m_view->setOperationMode(None); -} - -// static -void RazorManager::checkOperation(QGraphicsItem *item, CustomTrackView *view, QMouseEvent *event, int eventPos, OperationType &operationMode, bool &abort) -{ - if ((item != nullptr) && event->buttons() == Qt::NoButton && operationMode != ZoomTimeline) { - // razor tool over a clip, display current frame in monitor - if (event->modifiers() == Qt::ShiftModifier && item->type() == AVWidget) { - ClipItem *clip = static_cast(item); - QMetaObject::invokeMethod(view, "showClipFrame", Qt::QueuedConnection, Q_ARG(QString, clip->getBinId()), - Q_ARG(int, eventPos - (clip->startPos() - clip->cropStart()).frames(view->fps()))); - } - event->accept(); - abort = true; - } else { - // No clip under razor - event->accept(); - abort = true; - } -} - -void RazorManager::slotRefreshCutLine() -{ - if (m_cutLine) { - QPointF pos = m_view->mapToScene(m_view->mapFromGlobal(QCursor::pos())); - int mappedXPos = qMax((int)(pos.x()), 0); - m_cutLine->setPos(mappedXPos, m_view->getPositionFromTrack(m_view->getTrackFromPos(pos.y()))); - } -} diff --git a/src/timeline/managers/razormanager.h b/src/timeline/managers/razormanager.h deleted file mode 100644 index c6ea75133..000000000 --- a/src/timeline/managers/razormanager.h +++ /dev/null @@ -1,67 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef RAZORMANAGER_H -#define RAZORMANAGER_H - -#include "definitions.h" - -class QGraphicsItem; -class QMouseEvent; -class CustomTrackView; -class QGraphicsLineItem; - -#include "abstracttoolmanager.h" - -/** - * @namespace RazorManager - * @brief Provides convenience methods to handle selection tool. - */ - -class RazorManager : public AbstractToolManager -{ - Q_OBJECT - -public: - explicit RazorManager(CustomTrackView *view, std::shared_ptr commandStack); - bool mousePress(QMouseEvent *event, const ItemInfo &info = ItemInfo(), const QList &list = QList()) override; - bool mouseMove(QMouseEvent *event, int pos = 0, int track = -1) override; - void mouseRelease(QMouseEvent *event, GenTime pos = GenTime()) override; - void enterEvent(int pos, double trackHeight) override; - void leaveEvent() override; - void initTool(double trackHeight) override; - void closeTool() override; - /** @brief Check if a guide operation is applicable on items under mouse. - * @param items The list of items under mouse - * @param operationMode Will be set to MoveGuide if applicable - * @param abort Will be set to true if an operation matched and the items list should not be tested for further operation modes - **/ - static void checkOperation(QGraphicsItem *item, CustomTrackView *view, QMouseEvent *event, int eventPos, OperationType &operationMode, bool &abort); - -public slots: - void slotRefreshCutLine(); - void updateTimelineItems() override; - -private: - QGraphicsLineItem *m_cutLine; - QCursor m_cursor; - void buildCutLine(double trackHeight); -}; - -#endif diff --git a/src/timeline/managers/resizemanager.cpp b/src/timeline/managers/resizemanager.cpp deleted file mode 100644 index 1c49a4656..000000000 --- a/src/timeline/managers/resizemanager.cpp +++ /dev/null @@ -1,227 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "resizemanager.h" -#include "doc/docundostack.hpp" -#include "kdenlivesettings.h" -#include "timeline/abstractgroupitem.h" -#include "timeline/clipitem.h" -#include "timeline/customtrackview.h" -#include "timeline/timelinecommands.h" -#include "timeline/transition.h" - -#include - -ResizeManager::ResizeManager(CustomTrackView *view, std::shared_ptr commandStack) - : AbstractToolManager(ResizeType, view, commandStack) -{ -} - -bool ResizeManager::mousePress(QMouseEvent *event, const ItemInfo &info, const QList &) -{ - m_dragItemInfo = info; - m_controlModifier = event->modifiers(); - AbstractClipItem *dragItem = m_view->dragItem(); - AbstractGroupItem *selectionGroup = m_view->selectionGroup(); - if (selectionGroup) { - m_view->resetSelectionGroup(false); - dragItem->setSelected(true); - } - m_view->setOperationMode(m_view->prepareMode()); - m_startInfos.clear(); - if (dragItem->type() == AVWidget && (dragItem->parentItem() != nullptr)) { - // Store start infos - AbstractGroupItem *parent = static_cast(dragItem->parentItem()); - if (parent) { - QList items = parent->childItems(); - for (int i = 0; i < items.count(); ++i) { - if (items.at(i)->type() == AVWidget) { - AbstractClipItem *item = static_cast(items.at(i)); - m_startInfos << item->info(); - } - } - } - } - return true; -} - -bool ResizeManager::mouseMove(QMouseEvent *event, int pos, int) -{ - double snappedPos = m_view->getSnapPointForPos(pos); - if ((event->buttons() & Qt::LeftButton) != 0u) { - AbstractClipItem *dragItem = m_view->dragItem(); - if (!(m_controlModifier & Qt::ControlModifier) && dragItem->type() == AVWidget && (dragItem->parentItem() != nullptr)) { - AbstractGroupItem *parent = static_cast(dragItem->parentItem()); - if (parent) { - if (m_view->operationMode() == ResizeStart) { - parent->resizeStart(snappedPos); - } else { - parent->resizeEnd(snappedPos); - } - } - } else { - if (m_view->operationMode() == ResizeStart) { - dragItem->resizeStart(snappedPos, true, false); - } else { - dragItem->resizeEnd(snappedPos, false); - } - } - QString crop = m_view->timecode().getDisplayTimecode(dragItem->cropStart(), KdenliveSettings::frametimecode()); - QString duration = m_view->timecode().getDisplayTimecode(dragItem->cropDuration(), KdenliveSettings::frametimecode()); - QString offset = m_view->timecode().getDisplayTimecode(dragItem->cropStart() - m_dragItemInfo.cropStart, KdenliveSettings::frametimecode()); - m_view->displayMessage(i18n("Crop from start: %1 Duration: %2 Offset: %3", crop, duration, offset), InformationMessage); - event->accept(); - } - return true; -} - -void ResizeManager::mouseRelease(QMouseEvent *, GenTime pos) -{ - Q_UNUSED(pos); - AbstractClipItem *dragItem = m_view->dragItem(); - if (dragItem) { - if (m_view->operationMode() == ResizeStart) { - if (dragItem->startPos() != m_dragItemInfo.startPos) { - // resize start - if (/*!(m_controlModifier & Qt::ControlModifier) &&*/ dragItem->type() == AVWidget && (dragItem->parentItem() != nullptr)) { - AbstractGroupItem *parent = static_cast(dragItem->parentItem()); - if (parent) { - auto *resizeCommand = new QUndoCommand(); - resizeCommand->setText(i18n("Resize group")); - QList items = parent->childItems(); - GenTime min = parent->startPos(); - GenTime max = min; - int itemcount = 0; - for (int i = 0; i < items.count(); ++i) { - AbstractClipItem *item = static_cast(items.at(i)); - if ((item != nullptr) && item->type() == AVWidget) { - ItemInfo info = m_startInfos.at(itemcount); - m_view->prepareResizeClipStart(item, info, item->startPos().frames(m_view->fps()), false, resizeCommand); - ClipItem *cp = qobject_cast(item); - if ((cp != nullptr) && cp->hasVisibleVideo()) { - min = qMin(min, item->startPos()); - max = qMax(max, item->startPos()); - } - ++itemcount; - } - } - m_commandStack->push(resizeCommand); - if (min < max) { - ItemInfo nfo; - nfo.startPos = min; - nfo.endPos = max; - m_view->monitorRefresh(nfo, true); - } - } else { - qCDebug(KDENLIVE_LOG) << " * * * * *PARENT GRP NOT FOUND"; - } - } else { - m_view->prepareResizeClipStart(dragItem, m_dragItemInfo, dragItem->startPos().frames(m_view->fps())); - ItemInfo range; - range.track = m_dragItemInfo.track; - if (dragItem->startPos() < m_dragItemInfo.startPos) { - range.startPos = dragItem->startPos(); - range.endPos = m_dragItemInfo.startPos; - } else { - range.endPos = dragItem->startPos(); - range.startPos = m_dragItemInfo.startPos; - } - if (dragItem->type() == AVWidget) { - ClipItem *cp = qobject_cast(dragItem); - cp->slotUpdateRange(); - if (cp->hasVisibleVideo()) { - m_view->monitorRefresh(range, true); - } - m_view->clearSelection(); - delete dragItem; - m_view->reloadTrack(range, true); - dragItem = m_view->getClipItemAtEnd(m_dragItemInfo.endPos, m_dragItemInfo.track); - if (dragItem) { - m_view->slotSelectItem(dragItem); - } - } else { - // Resized transition - m_view->monitorRefresh(QList() << m_dragItemInfo << dragItem->info(), true); - } - if (!dragItem) { - qCDebug(KDENLIVE_LOG) << " * * ** SOMETHING WRONG HERE: " << m_dragItemInfo.endPos.frames(m_view->fps()); - } - } - } - } else if (m_view->operationMode() == ResizeEnd) { - dragItem->setProperty("resizingEnd", QVariant()); - if (dragItem->endPos() != m_dragItemInfo.endPos) { - if (!(m_controlModifier & Qt::ControlModifier) && dragItem->type() == AVWidget && (dragItem->parentItem() != nullptr)) { - AbstractGroupItem *parent = static_cast(dragItem->parentItem()); - if (parent) { - auto *resizeCommand = new QUndoCommand(); - resizeCommand->setText(i18n("Resize group")); - QList items = parent->childItems(); - GenTime min = parent->startPos() + parent->duration(); - GenTime max = min; - int itemcount = 0; - for (int i = 0; i < items.count(); ++i) { - AbstractClipItem *item = static_cast(items.at(i)); - if ((item != nullptr) && item->type() == AVWidget) { - ItemInfo info = m_startInfos.at(itemcount); - m_view->prepareResizeClipEnd(item, info, item->endPos().frames(m_view->fps()), false, resizeCommand); - ClipItem *cp = qobject_cast(item); - if ((cp != nullptr) && cp->hasVisibleVideo()) { - min = qMin(min, item->endPos()); - max = qMax(max, item->endPos()); - } - ++itemcount; - } - } - m_view->updateTrackDuration(-1, resizeCommand); - m_commandStack->push(resizeCommand); - if (min < max) { - ItemInfo nfo; - nfo.startPos = min; - nfo.endPos = max; - m_view->monitorRefresh(nfo, true); - } - } - } else { - m_view->prepareResizeClipEnd(dragItem, m_dragItemInfo, dragItem->endPos().frames(m_view->fps()), false); - ItemInfo range; - if (dragItem->endPos() < m_dragItemInfo.endPos) { - range.startPos = dragItem->endPos(); - range.endPos = m_dragItemInfo.endPos; - } else { - range.endPos = dragItem->endPos(); - range.startPos = m_dragItemInfo.endPos; - } - if (dragItem->type() == AVWidget) { - ClipItem *cp = qobject_cast(dragItem); - cp->slotUpdateRange(); - if (cp->hasVisibleVideo()) { - m_view->monitorRefresh(range, true); - } - } else { - m_view->monitorRefresh(QList() << m_dragItemInfo << dragItem->info(), true); - } - } - } - } - } - m_startInfos.clear(); - m_view->setCursor(Qt::OpenHandCursor); - m_view->setOperationMode(None); -} diff --git a/src/timeline/managers/resizemanager.h b/src/timeline/managers/resizemanager.h deleted file mode 100644 index 680bef8be..000000000 --- a/src/timeline/managers/resizemanager.h +++ /dev/null @@ -1,46 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef RESIZEEMANAGER_H -#define RESIZEEMANAGER_H - -#include "abstracttoolmanager.h" - -/** - * @namespace ResizeManager - * @brief Provides convenience methods to handle selection tool. - */ - -class ResizeManager : public AbstractToolManager -{ - Q_OBJECT - -public: - explicit ResizeManager(CustomTrackView *view, std::shared_ptr commandStack); - bool mousePress(QMouseEvent *event, const ItemInfo &info = ItemInfo(), const QList &list = QList()) override; - bool mouseMove(QMouseEvent *event, int pos = 0, int track = -1) override; - void mouseRelease(QMouseEvent *event, GenTime pos = GenTime()) override; - -private: - ItemInfo m_dragItemInfo; - QList m_startInfos; - Qt::KeyboardModifiers m_controlModifier; -}; - -#endif diff --git a/src/timeline/managers/selectmanager.cpp b/src/timeline/managers/selectmanager.cpp deleted file mode 100644 index a81ed45bf..000000000 --- a/src/timeline/managers/selectmanager.cpp +++ /dev/null @@ -1,406 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "selectmanager.h" -#include "doc/docundostack.hpp" -#include "kdenlivesettings.h" -#include "mainwindow.h" -#include "timeline/abstractgroupitem.h" -#include "timeline/clipitem.h" -#include "timeline/customtrackview.h" -#include "timeline/timelinecommands.h" - -#include -#include - -#include - -#include "klocalizedstring.h" - -SelectManager::SelectManager(CustomTrackView *view, std::shared_ptr commandStack) - : AbstractToolManager(SelectType, view, commandStack) - , m_dragMoved(false) -{ -} - -bool SelectManager::mousePress(QMouseEvent *event, const ItemInfo &info, const QList &) -{ - Q_UNUSED(info); - m_view->activateMonitor(); - m_modifiers = event->modifiers(); - m_dragMoved = false; - m_clickPoint = event->pos(); - if ((m_modifiers & Qt::ShiftModifier) != 0u) { - m_view->createRectangleSelection(event->modifiers()); - return true; - } - // No item under click - AbstractClipItem *dragItem = m_view->dragItem(); - if (dragItem == nullptr) { - m_view->clearSelection(true); - if (event->button() == Qt::LeftButton) { - m_view->setOperationMode(Seek); - m_view->seekCursorPos((int)m_view->mapToScene(event->pos()).x()); - event->setAccepted(true); - return true; - } - } else { - m_view->setOperationMode(m_view->prepareMode()); - } - switch (m_view->operationMode()) { - case FadeIn: - case FadeOut: - // m_view->setCursor(Qt::PointingHandCursor); - break; - case KeyFrame: - // m_view->setCursor(Qt::PointingHandCursor); - dragItem->prepareKeyframeMove(); - break; - default: - // m_view->setCursor(Qt::ArrowCursor); - break; - } - return false; -} - -bool SelectManager::mouseMove(QMouseEvent *event, int, int) -{ - OperationType mode = m_view->operationMode(); - if (mode == Seek) { - return false; - } - if (!m_dragMoved && ((event->buttons() & Qt::LeftButton) != 0u)) { - if ((m_clickPoint - event->pos()).manhattanLength() < QApplication::startDragDistance()) { - event->ignore(); - return true; - } - m_dragMoved = true; - } - if (mode == FadeIn) { - AbstractClipItem *dragItem = m_view->dragItem(); - double mappedXPos = m_view->mapToScene(event->pos()).x(); - static_cast(dragItem)->setFadeIn(static_cast(mappedXPos - dragItem->startPos().frames(m_view->fps()))); - event->accept(); - return true; - } - if (mode == FadeOut) { - AbstractClipItem *dragItem = m_view->dragItem(); - double mappedXPos = m_view->mapToScene(event->pos()).x(); - static_cast(dragItem)->setFadeOut(static_cast(dragItem->endPos().frames(m_view->fps()) - mappedXPos)); - event->accept(); - return true; - } - if (mode == KeyFrame) { - AbstractClipItem *dragItem = m_view->dragItem(); - double mappedXPos = m_view->mapToScene(event->pos()).x(); - GenTime keyFramePos = GenTime(mappedXPos, m_view->fps()) - dragItem->startPos(); - double value = dragItem->mapFromScene(m_view->mapToScene(event->pos()).toPoint()).y(); - dragItem->updateKeyFramePos(keyFramePos.frames(m_view->fps()), value); - QString position = m_view->timecode().getDisplayTimecodeFromFrames(dragItem->selectedKeyFramePos(), KdenliveSettings::frametimecode()); - m_view->displayMessage(position + QStringLiteral(" : ") + QString::number(dragItem->editedKeyFrameValue()), InformationMessage); - event->accept(); - return true; - } - return false; -} - -void SelectManager::mouseRelease(QMouseEvent *event, GenTime pos) -{ - Q_UNUSED(pos); - AbstractClipItem *dragItem = m_view->dragItem(); - OperationType moveType = m_view->operationMode(); - if (moveType == RubberSelection) { - // setViewportUpdateMode(QGraphicsView::MinimalViewportUpdate); - if (event->modifiers() != Qt::ControlModifier) { - if (dragItem) { - dragItem->setMainSelectedClip(false); - } - dragItem = nullptr; - } - event->accept(); - m_view->resetSelectionGroup(); - m_view->groupSelectedItems(); - if (m_view->selectionGroup() == nullptr && (dragItem != nullptr)) { - // Only 1 item selected - if (dragItem->type() == AVWidget) { - dragItem->setMainSelectedClip(true); - m_view->clipItemSelected(static_cast(dragItem), false); - } - } - return; - } - if (!m_dragMoved) { - return; - } - if (moveType == Seek || moveType == WaitingForConfirm || moveType == None || (!m_dragMoved && moveType == MoveOperation)) { - if (!(m_modifiers & Qt::ControlModifier)) { - if (dragItem) { - dragItem->setMainSelectedClip(false); - } - dragItem = nullptr; - } - m_view->resetSelectionGroup(); - m_view->groupSelectedItems(); - AbstractGroupItem *selectionGroup = m_view->selectionGroup(); - if (selectionGroup == nullptr && (dragItem != nullptr)) { - // Only 1 item selected - if (dragItem->type() == AVWidget) { - dragItem->setMainSelectedClip(true); - m_view->clipItemSelected(static_cast(dragItem), false); - } - } - } - if (moveType == FadeIn && (dragItem != nullptr)) { - ClipItem *item = static_cast(dragItem); - // find existing video fade, if none then audio fade - - int fadeIndex = item->hasEffect(QString(), QStringLiteral("fade_from_black")); - int fadeIndex2 = item->hasEffect(QStringLiteral("volume"), QStringLiteral("fadein")); - if (fadeIndex >= 0 && fadeIndex2 >= 0) { - // We have 2 fadin effects, use currently selected or first one - int current = item->selectedEffectIndex(); - if (fadeIndex != current) { - if (fadeIndex2 == current) { - fadeIndex = current; - } else { - fadeIndex = qMin(fadeIndex, fadeIndex2); - } - } - } else { - fadeIndex = qMax(fadeIndex, fadeIndex2); - } - // resize fade in effect - if (fadeIndex >= 0) { - QDomElement oldeffect = item->effectAtIndex(fadeIndex); - int end = item->fadeIn(); - if (end == 0) { - m_view->slotDeleteEffect(item, -1, oldeffect, false); - } else { - int start = item->cropStart().frames(m_view->fps()); - end += start; - QDomElement effect = oldeffect.cloneNode().toElement(); - EffectsList::setParameter(oldeffect, QStringLiteral("in"), QString::number(start)); - EffectsList::setParameter(oldeffect, QStringLiteral("out"), QString::number(end)); - m_view->slotUpdateClipEffect(item, -1, effect, oldeffect, fadeIndex); - m_view->clipItemSelected(item); - } - // new fade in - } else if (item->fadeIn() != 0) { - QDomElement effect; - if (item->clipState() == PlaylistState::VideoOnly || - (item->clipType() != Audio && item->clipState() != PlaylistState::AudioOnly && item->clipType() != Playlist)) { - effect = MainWindow::videoEffects.getEffectByTag(QString(), QStringLiteral("fade_from_black")).cloneNode().toElement(); - } else { - effect = MainWindow::audioEffects.getEffectByTag(QStringLiteral("volume"), QStringLiteral("fadein")).cloneNode().toElement(); - } - EffectsList::setParameter(effect, QStringLiteral("out"), QString::number(item->fadeIn())); - m_view->slotAddEffect(effect, dragItem->startPos(), dragItem->track()); - } - - } else if (moveType == FadeOut && (dragItem != nullptr)) { - ClipItem *item = static_cast(dragItem); - // find existing video fade, if none then audio fade - - int fadeIndex = item->hasEffect(QString(), QStringLiteral("fade_to_black")); - int fadeIndex2 = item->hasEffect(QStringLiteral("volume"), QStringLiteral("fadeout")); - if (fadeIndex >= 0 && fadeIndex2 >= 0) { - // We have 2 fadin effects, use currently selected or first one - int current = item->selectedEffectIndex(); - if (fadeIndex != current) { - if (fadeIndex2 == current) { - fadeIndex = current; - } else { - fadeIndex = qMin(fadeIndex, fadeIndex2); - } - } - } else { - fadeIndex = qMax(fadeIndex, fadeIndex2); - } - // resize fade out effect - if (fadeIndex >= 0) { - QDomElement oldeffect = item->effectAtIndex(fadeIndex); - int start = item->fadeOut(); - if (start == 0) { - m_view->slotDeleteEffect(item, -1, oldeffect, false); - } else { - int end = (item->cropDuration() + item->cropStart()).frames(m_view->fps()); - start = end - start; - QDomElement effect = oldeffect.cloneNode().toElement(); - EffectsList::setParameter(oldeffect, QStringLiteral("in"), QString::number(start)); - EffectsList::setParameter(oldeffect, QStringLiteral("out"), QString::number(end)); - m_view->slotUpdateClipEffect(item, -1, effect, oldeffect, fadeIndex); - m_view->clipItemSelected(item); - } - // new fade out - } else if (item->fadeOut() != 0) { - QDomElement effect; - if (item->clipState() == PlaylistState::VideoOnly || - (item->clipType() != Audio && item->clipState() != PlaylistState::AudioOnly && item->clipType() != Playlist)) { - effect = MainWindow::videoEffects.getEffectByTag(QString(), QStringLiteral("fade_to_black")).cloneNode().toElement(); - } else { - effect = MainWindow::audioEffects.getEffectByTag(QStringLiteral("volume"), QStringLiteral("fadeout")).cloneNode().toElement(); - } - int end = (item->cropDuration() + item->cropStart()).frames(m_view->fps()); - int start = end - item->fadeOut(); - EffectsList::setParameter(effect, QStringLiteral("in"), QString::number(start)); - EffectsList::setParameter(effect, QStringLiteral("out"), QString::number(end)); - m_view->slotAddEffect(effect, dragItem->startPos(), dragItem->track()); - } - - } else if (moveType == KeyFrame && (dragItem != nullptr) && m_dragMoved) { - // update the MLT effect - ClipItem *item = static_cast(dragItem); - QDomElement oldEffect = item->selectedEffect().cloneNode().toElement(); - - // check if we want to remove keyframe - double val = m_view->mapToScene(event->pos()).toPoint().y(); - QRectF br = item->sceneBoundingRect(); - double maxh = 100.0 / br.height(); - val = (br.bottom() - val) * maxh; - int start = item->cropStart().frames(m_view->fps()); - int end = (item->cropStart() + item->cropDuration()).frames(m_view->fps()) - 1; - - if ((val < -50 || val > 150) && item->selectedKeyFramePos() != start && item->selectedKeyFramePos() != end && item->keyframesCount() > 1) { - // delete keyframe - item->removeKeyframe(item->getEffectAtIndex(item->selectedEffectIndex()), item->selectedKeyFramePos()); - } else { - item->movedKeyframe(item->getEffectAtIndex(item->selectedEffectIndex()), item->selectedKeyFramePos(), item->originalKeyFramePos()); - } - - QDomElement newEffect = item->selectedEffect().cloneNode().toElement(); - - EditEffectCommand *command = - new EditEffectCommand(m_view, item->track(), item->startPos(), oldEffect, newEffect, item->selectedEffectIndex(), false, false, true); - m_commandStack->push(command); - m_view->updateEffect(item->track(), item->startPos(), item->selectedEffect()); - m_view->clipItemSelected(item); - } else if (moveType == KeyFrame && (dragItem != nullptr)) { - m_view->setActiveKeyframe(dragItem->selectedKeyFramePos()); - } -} - -void SelectManager::initTool(double) -{ - m_view->unsetCursor(); -} - -void SelectManager::checkOperation(QGraphicsItem *item, CustomTrackView *view, QMouseEvent *event, AbstractGroupItem *group, OperationType &operationMode, - OperationType moveOperation) -{ - OperationType currentMode = operationMode; - if ((item != nullptr) && event->buttons() == Qt::NoButton && operationMode != ZoomTimeline) { - AbstractClipItem *clip = static_cast(item); - QString tooltipMessage; - - if ((group != nullptr) && clip->parentItem() == group) { - // all other modes break the selection, so the user probably wants to move it - operationMode = MoveOperation; - } else { - if (clip->rect().width() * view->transform().m11() < 15) { - // If the item is very small, only allow move - operationMode = MoveOperation; - } else { - operationMode = clip->operationMode(clip->mapFromScene(view->mapToScene(event->pos())), event->modifiers()); - } - } - - if (operationMode == moveOperation) { - view->graphicsViewMouseEvent(event); - if (currentMode != operationMode) { - view->setToolTip(tooltipMessage); - } - return; - } - ClipItem *ci = nullptr; - if (item->type() == AVWidget) { - ci = static_cast(item); - } - QString message; - if (operationMode == MoveOperation) { - view->setCursor(Qt::OpenHandCursor); - if (ci) { - message = ci->clipName() + i18n(":"); - message.append(i18n(" Position:") + view->getDisplayTimecode(ci->info().startPos)); - message.append(i18n(" Duration:") + view->getDisplayTimecode(ci->cropDuration())); - if ((clip->parentItem() != nullptr) && clip->parentItem()->type() == GroupWidget) { - AbstractGroupItem *parent = static_cast(clip->parentItem()); - if (clip->parentItem() == group) { - message.append(i18n(" Selection duration:")); - } else { - message.append(i18n(" Group duration:")); - } - message.append(view->getDisplayTimecode(parent->duration())); - if ((parent->parentItem() != nullptr) && parent->parentItem()->type() == GroupWidget) { - AbstractGroupItem *parent2 = static_cast(parent->parentItem()); - message.append(i18n(" Selection duration:") + view->getDisplayTimecode(parent2->duration())); - } - } - } - } else if (operationMode == ResizeStart) { - view->setCursor(QCursor(Qt::SizeHorCursor)); - if (ci) { - message = i18n("Crop from start: ") + view->getDisplayTimecode(ci->cropStart()); - } - if (item->type() == AVWidget && (item->parentItem() != nullptr) && item->parentItem() != group) { - message.append(i18n("Use Ctrl to resize only current item, otherwise all items in this group will be resized at once.")); - } - } else if (operationMode == ResizeEnd) { - view->setCursor(QCursor(Qt::SizeHorCursor)); - if (ci) { - message = i18n("Duration: ") + view->getDisplayTimecode(ci->cropDuration()); - } - if (item->type() == AVWidget && (item->parentItem() != nullptr) && item->parentItem() != group) { - message.append(i18n("Use Ctrl to resize only current item, otherwise all items in this group will be resized at once.")); - } - } else if (operationMode == FadeIn || operationMode == FadeOut) { - view->setCursor(Qt::PointingHandCursor); - if ((ci != nullptr) && operationMode == FadeIn && (ci->fadeIn() != 0)) { - message = i18n("Fade in duration: "); - message.append(view->getDisplayTimecodeFromFrames(ci->fadeIn())); - } else if ((ci != nullptr) && operationMode == FadeOut && (ci->fadeOut() != 0)) { - message = i18n("Fade out duration: "); - message.append(view->getDisplayTimecodeFromFrames(ci->fadeOut())); - } else { - message = i18n("Drag to add or resize a fade effect."); - tooltipMessage = message; - } - } else if (operationMode == TransitionStart || operationMode == TransitionEnd) { - view->setCursor(Qt::PointingHandCursor); - message = i18n("Click to add a transition."); - tooltipMessage = message; - } else if (operationMode == KeyFrame) { - view->setCursor(Qt::PointingHandCursor); - QMetaObject::invokeMethod(view, "displayMessage", Qt::QueuedConnection, - Q_ARG(QString, i18n("Move keyframe above or below clip to remove it, double click to add a new one.")), - Q_ARG(MessageType, InformationMessage)); - } - if (currentMode != operationMode) { - view->setToolTip(tooltipMessage); - } - if (!message.isEmpty()) { - QMetaObject::invokeMethod(view, "displayMessage", Qt::QueuedConnection, Q_ARG(QString, message), Q_ARG(MessageType, InformationMessage)); - } - } else if (event->buttons() == Qt::NoButton && (moveOperation == None || moveOperation == WaitingForConfirm)) { - operationMode = None; - if (currentMode != operationMode) { - view->setToolTip(QString()); - } - view->setCursor(Qt::ArrowCursor); - } -} diff --git a/src/timeline/managers/selectmanager.h b/src/timeline/managers/selectmanager.h deleted file mode 100644 index 7c132b100..000000000 --- a/src/timeline/managers/selectmanager.h +++ /dev/null @@ -1,59 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef SELECTMANAGER_H -#define SELECTMANAGER_H - -#include "abstracttoolmanager.h" - -class QGraphicsItem; -class QMouseEvent; -class CustomTrackView; -class AbstractGroupItem; - -/** - * @namespace SelectManager - * @brief Provides convenience methods to handle selection tool. - */ - -class SelectManager : public AbstractToolManager -{ - Q_OBJECT - -public: - explicit SelectManager(CustomTrackView *view, std::shared_ptr commandStack); - bool mousePress(QMouseEvent *event, const ItemInfo &info = ItemInfo(), const QList &list = QList()) override; - void mouseRelease(QMouseEvent *event, GenTime pos = GenTime()) override; - bool mouseMove(QMouseEvent *event, int pos, int) override; - /** @brief Check if a guide operation is applicable on items under mouse. - * @param item The item under mouse - * @param operationMode Will be set to under mouse operation if applicable - * @param abort Will be set to true if an operation matched and the items list should not be tested for further operation modes - **/ - static void checkOperation(QGraphicsItem *item, CustomTrackView *view, QMouseEvent *event, AbstractGroupItem *group, OperationType &operationMode, - OperationType moveOperation); - void initTool(double trackHeight) override; - -private: - Qt::KeyboardModifiers m_modifiers; - bool m_dragMoved; - QPoint m_clickPoint; -}; - -#endif diff --git a/src/timeline/managers/spacermanager.cpp b/src/timeline/managers/spacermanager.cpp deleted file mode 100644 index 5aa2048dc..000000000 --- a/src/timeline/managers/spacermanager.cpp +++ /dev/null @@ -1,99 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "spacermanager.h" -#include "timeline/abstractgroupitem.h" -#include "timeline/clipitem.h" -#include "timeline/customtrackview.h" - -#include -#include -#include - -SpacerManager::SpacerManager(CustomTrackView *view, std::shared_ptr commandStack) - : AbstractToolManager(SpacerType, view, std::move(commandStack)) - , m_track(0) - , m_dragMoved(false) -{ -} - -bool SpacerManager::mousePress(QMouseEvent *event, const ItemInfo &info, const QList &) -{ - m_view->clearSelection(); - m_view->updateClipTypeActions(nullptr); - m_view->setOperationMode(Spacer); - m_dragMoved = false; - m_clickPoint = event->pos(); - QList selection; - if ((event->modifiers() & Qt::ControlModifier) != 0u) { - // Ctrl + click, select all items on track after click position - m_track = info.track; - if (m_view->spaceToolSelectTrackOnly(info.track, selection) != 0) { - event->accept(); - return false; - } - } else { - m_track = -1; - // Select all items on all tracks after click position - selection = m_view->selectAllItemsToTheRight(info.startPos.frames(m_view->fps())); - } - m_startPos = m_view->createGroupForSelectedItems(selection); - m_spacerOffset = m_startPos - info.startPos; - event->accept(); - return false; -} - -void SpacerManager::initTool(double) -{ - qCDebug(KDENLIVE_LOG) << "* ** INIT SPACER"; - m_view->setCursor(Qt::SplitHCursor); -} - -bool SpacerManager::mouseMove(QMouseEvent *event, int pos, int) -{ - if ((event->buttons() & Qt::LeftButton) != 0u) { - if (!m_dragMoved) { - if ((m_clickPoint - event->pos()).manhattanLength() < QApplication::startDragDistance()) { - event->ignore(); - return false; - } - m_dragMoved = true; - } - int snappedPos = m_view->getSnapPointForPos(pos + m_spacerOffset.frames(m_view->fps())); - if (snappedPos < 0) { - snappedPos = 0; - } - m_view->spaceToolMoveToSnapPos(snappedPos); - event->accept(); - return true; - } - return false; -} - -void SpacerManager::mouseRelease(QMouseEvent *, GenTime pos) -{ - // GenTime timeOffset = pos - m_startPos; - Q_UNUSED(pos); - if (!m_dragMoved || (m_view->selectionGroup() == nullptr)) { - m_view->clearSelection(); - return; - } - GenTime timeOffset = GenTime(m_view->selectionGroup()->sceneBoundingRect().left(), m_view->fps()) - m_startPos; - m_view->completeSpaceOperation(m_track, timeOffset); -} diff --git a/src/timeline/managers/spacermanager.h b/src/timeline/managers/spacermanager.h deleted file mode 100644 index 277a04ab4..000000000 --- a/src/timeline/managers/spacermanager.h +++ /dev/null @@ -1,49 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef SPACERMANAGER_H -#define SPACERMANAGER_H - -#include "abstracttoolmanager.h" - -/** - * @namespace SpacerManager - * @brief Provides convenience methods to handle selection tool. - */ - -class SpacerManager : public AbstractToolManager -{ - Q_OBJECT - -public: - explicit SpacerManager(CustomTrackView *view, std::shared_ptr commandStack); - bool mousePress(QMouseEvent *event, const ItemInfo &info = ItemInfo(), const QList &list = QList()) override; - bool mouseMove(QMouseEvent *event, int pos = 0, int track = -1) override; - void mouseRelease(QMouseEvent *event, GenTime pos = GenTime()) override; - void initTool(double trackHeight) override; - -private: - int m_track; - GenTime m_startPos; - GenTime m_spacerOffset; - bool m_dragMoved; - QPoint m_clickPoint; -}; - -#endif diff --git a/src/timeline/managers/trimmanager.cpp b/src/timeline/managers/trimmanager.cpp deleted file mode 100644 index 5a47423c4..000000000 --- a/src/timeline/managers/trimmanager.cpp +++ /dev/null @@ -1,247 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "trimmanager.h" -#include "doc/docundostack.hpp" -#include "kdenlivesettings.h" -#include "renderer.h" -#include "timeline/clipitem.h" -#include "timeline/customtrackview.h" - -#include -#include -#include - -TrimManager::TrimManager(CustomTrackView *view, std::shared_ptr commandStack) - : AbstractToolManager(TrimType, view, commandStack) - , m_firstClip(nullptr) - , m_secondClip(nullptr) - , m_trimMode(NormalTrim) - , m_rippleIndex(0) - , m_trimPlaylist(nullptr) - , trimChanged(false) - , m_render(nullptr) -{ -} - -bool TrimManager::mousePress(QMouseEvent *, const ItemInfo &info, const QList &) -{ - return enterTrimMode(info, m_view->prepareMode() == ResizeStart); -} - -bool TrimManager::mouseMove(QMouseEvent *event, int pos, int) -{ - if ((event->buttons() & Qt::LeftButton) != 0u) { - if (!m_firstInfo.isValid() || !m_secondInfo.isValid()) { - return false; - } - double snappedPos = m_view->getSnapPointForPos(pos); - if (snappedPos < m_firstClip->endPos().frames(m_view->fps())) { - m_firstClip->resizeEnd(snappedPos, false); - m_secondClip->resizeStart(snappedPos, true, false); - } else { - m_secondClip->resizeStart(snappedPos, true, false); - m_firstClip->resizeEnd(snappedPos, false); - } - m_view->seekCursorPos(snappedPos); - return true; - } - return false; -} - -void TrimManager::mouseRelease(QMouseEvent *, GenTime) -{ - endTrim(); -} - -bool TrimManager::enterTrimMode(const ItemInfo &info, bool trimStart) -{ - m_view->loadMonitorScene(MonitorSceneRipple, true); - m_view->setQmlProperty(QStringLiteral("trimmode"), (int)m_trimMode); - if (m_trimMode == RollingTrim || m_trimMode == RippleTrim) { - if (trimStart) { - m_firstClip = m_view->getClipItemAtEnd(info.startPos, info.track); - m_secondClip = m_view->getClipItemAtStart(info.startPos, info.track); - } else { - m_firstClip = m_view->getClipItemAtEnd(info.endPos, info.track); - m_secondClip = m_view->getClipItemAtStart(info.endPos, info.track); - } - if ((m_firstClip == nullptr) || (m_secondClip == nullptr)) { - m_view->displayMessage(i18n("Could not find necessary clips to perform rolling trim"), InformationMessage); - m_view->setOperationMode(None); - m_firstInfo = ItemInfo(); - m_secondInfo = ItemInfo(); - return false; - } - AbstractClipItem *dragItem = m_view->dragItem(); - AbstractGroupItem *selectionGroup = m_view->selectionGroup(); - if (selectionGroup) { - m_view->resetSelectionGroup(false); - dragItem->setSelected(true); - } - m_firstInfo = m_firstClip->info(); - m_secondInfo = m_secondClip->info(); - if (m_trimMode == RollingTrim) { - m_view->setOperationMode(trimStart ? RollingStart : RollingEnd); - } else if (m_trimMode == RippleTrim) { - m_view->setOperationMode(trimStart ? RippleStart : RippleEnd); - } - m_view->trimMode(true, m_secondInfo.startPos.frames(m_view->fps())); - m_view->seekCursorPos(trimStart ? info.startPos.frames(m_view->fps()) : info.endPos.frames(m_view->fps())); - } - if (m_trimMode == RippleTrim) { - m_render->byPassSeek = true; - connect(m_render, &Render::renderSeek, this, &TrimManager::renderSeekRequest, Qt::UniqueConnection); - } else if (m_render->byPassSeek) { - m_render->byPassSeek = false; - disconnect(m_render, &Render::renderSeek, this, &TrimManager::renderSeekRequest); - } - return true; -} - -void TrimManager::initRipple(Mlt::Playlist *playlist, int pos, Render *renderer) -{ - m_render = renderer; - connect(renderer, &Render::renderSeek, this, &TrimManager::renderSeekRequest); - m_trimPlaylist = playlist; - m_rippleIndex = playlist->get_clip_index_at(pos); -} - -void TrimManager::renderSeekRequest(int diff) -{ - qCDebug(KDENLIVE_LOG) << " + + +RIPPLE DIFF: " << diff; - Mlt::ClipInfo *cInfo = m_trimPlaylist->clip_info(m_rippleIndex); - int in = cInfo->frame_in; - int out = cInfo->frame_out; - qCDebug(KDENLIVE_LOG) << "* * *RESITE CLIP FIRST IN: " << in << "-" << out << ", " << cInfo->start << ", " << cInfo->length; - delete cInfo; - ClipItem *clipToRipple = nullptr; - if (m_view->operationMode() == RippleStart) { - in -= diff; - clipToRipple = m_secondClip; - } else { - out += diff; - clipToRipple = m_firstClip; - m_render->seekToFrame(m_firstClip->endPos().frames(m_view->fps()) + diff); - } - qCDebug(KDENLIVE_LOG) << "* * *RESITE CLIP IN: " << in; - m_trimPlaylist->resize_clip(m_rippleIndex, in, out); - m_render->doRefresh(); - m_view->rippleClip(clipToRipple, diff); - trimChanged = true; -} - -void TrimManager::moveRoll(bool forward, int pos) -{ - if (!m_firstInfo.isValid() || !m_secondInfo.isValid()) { - return; - } - if (pos == -1) { - pos = m_firstClip->endPos().frames(m_view->fps()); - if (forward) { - pos++; - } else { - pos--; - } - } - bool snap = KdenliveSettings::snaptopoints(); - KdenliveSettings::setSnaptopoints(false); - if (forward) { - m_secondClip->resizeStart(pos, true, false); - m_firstClip->resizeEnd(pos, false); - } else { - m_firstClip->resizeEnd(pos, false); - m_secondClip->resizeStart(pos, true, false); - } - // m_view->seekCursorPos(pos); - KdenliveSettings::setSnaptopoints(snap); - trimChanged = true; -} - -void TrimManager::endTrim() -{ - m_view->trimMode(false); - if (!m_firstInfo.isValid() || !m_secondInfo.isValid()) { - return; - } - if (m_render->byPassSeek) { - m_render->byPassSeek = false; - disconnect(m_render, &Render::renderSeek, this, &TrimManager::renderSeekRequest); - } - if (m_view->operationMode() == RippleStart || m_view->operationMode() == RippleEnd) { - delete m_trimPlaylist; - m_trimPlaylist = nullptr; - if (m_view->operationMode() == RippleStart) { - m_view->finishRipple(m_secondClip, m_secondInfo, (m_secondInfo.endPos - m_secondClip->endPos()).frames(m_view->fps()), true); - } else { - m_view->finishRipple(m_firstClip, m_firstInfo, (m_firstClip->endPos() - m_firstInfo.endPos).frames(m_view->fps()), false); - } - // TODO: integrate in undo/redo framework - return; - } - if (m_view->operationMode() == RollingStart || m_view->operationMode() == RollingEnd) { - auto *command = new QUndoCommand; - command->setText(i18n("Rolling Edit")); - if (m_firstClip->endPos() < m_firstInfo.endPos) { - m_view->prepareResizeClipEnd(m_firstClip, m_firstInfo, m_firstClip->startPos().frames(m_view->fps()), false, command); - m_view->prepareResizeClipStart(m_secondClip, m_secondInfo, m_secondClip->startPos().frames(m_view->fps()), false, command); - } else { - m_view->prepareResizeClipStart(m_secondClip, m_secondInfo, m_secondClip->startPos().frames(m_view->fps()), false, command); - m_view->prepareResizeClipEnd(m_firstClip, m_firstInfo, m_firstClip->startPos().frames(m_view->fps()), false, command); - } - m_commandStack->push(command); - m_firstInfo = ItemInfo(); - m_secondInfo = ItemInfo(); - } -} - -TrimMode TrimManager::trimMode() const -{ - return m_trimMode; -} - -void TrimManager::setTrimMode(TrimMode mode, const ItemInfo &info, bool fromStart) -{ - m_trimMode = mode; - if (trimChanged && mode != NormalTrim) { - endTrim(); - } - QString modeLabel; - switch (m_trimMode) { - case RippleTrim: - modeLabel = i18n(" Ripple "); - break; - case RollingTrim: - modeLabel = i18n(" Rolling "); - break; - case SlideTrim: - modeLabel = i18n(" Slide "); - break; - case SlipTrim: - modeLabel = i18n(" Slip "); - break; - default: - emit updateTrimMode(modeLabel); - endTrim(); - return; - break; - } - emit updateTrimMode(modeLabel); - enterTrimMode(info, fromStart); -} diff --git a/src/timeline/managers/trimmanager.h b/src/timeline/managers/trimmanager.h deleted file mode 100644 index 1f1fe07f1..000000000 --- a/src/timeline/managers/trimmanager.h +++ /dev/null @@ -1,73 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2016 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TRIMMANAGER_H -#define TRIMMANAGER_H - -#include "abstracttoolmanager.h" - -class ClipItem; -class Render; -namespace Mlt { -class Playlist; -} - -/** - * @namespace TrimManager - * @brief Provides convenience methods to handle selection tool. - */ - -class TrimManager : public AbstractToolManager -{ - Q_OBJECT - -public: - explicit TrimManager(CustomTrackView *view, std::shared_ptr commandStack); - bool mousePress(QMouseEvent *event, const ItemInfo &info = ItemInfo(), const QList &list = QList()) override; - bool mouseMove(QMouseEvent *event, int pos, int track = -1) override; - void mouseRelease(QMouseEvent *event, GenTime pos = GenTime()) override; - bool enterTrimMode(const ItemInfo &info, bool trimStart); - void moveRoll(bool forward, int pos = -1); - void setTrimMode(TrimMode mode, const ItemInfo &info = ItemInfo(), bool fromStart = true); - TrimMode trimMode() const; - void initRipple(Mlt::Playlist *playlist, int pos, Render *renderer); - -public slots: - void endTrim(); - -private slots: - void renderSeekRequest(int diff); - -private: - ClipItem *m_firstClip; - ClipItem *m_secondClip; - ItemInfo m_firstInfo; - ItemInfo m_secondInfo; - TrimMode m_trimMode; - int m_rippleIndex; - Mlt::Playlist *m_trimPlaylist; - bool trimChanged; - Render *m_render; - void closeRipple(); - -signals: - void updateTrimMode(const QString &); -}; - -#endif diff --git a/src/timeline/spacerdialog.cpp b/src/timeline/spacerdialog.cpp deleted file mode 100644 index ebe7341e3..000000000 --- a/src/timeline/spacerdialog.cpp +++ /dev/null @@ -1,76 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "spacerdialog.h" - -#include "doc/kthumb.h" -#include "kdenlivesettings.h" - -#include -#include - -#include "klocalizedstring.h" - -// deprecated -SpacerDialog::SpacerDialog(const GenTime &duration, const Timecode &tc, int track, const QList &tracks, QWidget *parent) - : QDialog(parent) - , m_in(tc) -{ - setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); - setupUi(this); - inputLayout->addWidget(&m_in); - m_in.setValue(duration); - - /*QIcon videoIcon = QIcon::fromTheme(QStringLiteral("kdenlive-show-video")); - QIcon audioIcon = QIcon::fromTheme(QStringLiteral("kdenlive-show-audio")); - track_number->addItem(i18n("All tracks"), -1); - for (int i = tracks.count() - 1; i > 0; i--) { - TrackInfo info = tracks.at(i); - track_number->addItem(info.type == VideoTrack ? videoIcon : audioIcon, info.trackName.isEmpty() ? QString::number(i) : info.trackName, i); - } - track_number->setCurrentIndex(track == 0 ? 0 : tracks.count() - track); - */ - adjustSize(); -} - -SpacerDialog::SpacerDialog(const GenTime &duration, const Timecode &tc, QWidget *parent) - : QDialog(parent) - , m_in(tc) -{ - setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); - setupUi(this); - inputLayout->addWidget(&m_in); - m_in.setValue(duration); - adjustSize(); -} - -GenTime SpacerDialog::selectedDuration() const -{ - return m_in.gentime(); -} - -bool SpacerDialog::affectAllTracks() const -{ - return insert_all_tracks->isChecked(); -} - -int SpacerDialog::selectedTrack() const -{ - return 0; //track_number->currentData().toInt(); -} diff --git a/src/timeline/spacerdialog.h b/src/timeline/spacerdialog.h deleted file mode 100644 index dcb911c3b..000000000 --- a/src/timeline/spacerdialog.h +++ /dev/null @@ -1,49 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef SPACERDIALOG_H -#define SPACERDIALOG_H - -#include "definitions.h" -#include "timecode.h" -#include "timecodedisplay.h" -#include "ui_spacerdialog_ui.h" - -/** - * @class SpacerDialog - * @brief A dialog to specify length and track of inserted space. - * @author Jean-Baptiste Mardelle - */ - -class SpacerDialog : public QDialog, public Ui::SpacerDialog_UI -{ - Q_OBJECT - -public: - SpacerDialog(const GenTime &duration, const Timecode &tc, int track, const QList &tracks, QWidget *parent = nullptr); - SpacerDialog(const GenTime &duration, const Timecode &tc, QWidget *parent = nullptr); - GenTime selectedDuration() const; - int selectedTrack() const; - bool affectAllTracks() const; - -private: - TimecodeDisplay m_in; -}; - -#endif diff --git a/src/timeline/timeline.cpp b/src/timeline/timeline.cpp deleted file mode 100644 index 3e409b48a..000000000 --- a/src/timeline/timeline.cpp +++ /dev/null @@ -1,2164 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * Copyright (C) 2015 by Vincent Pinon (vpinon@kde.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "timeline.h" -#include "bin/projectclip.h" -#include "clip.h" -#include "clipitem.h" -#include "core.h" -#include "customruler.h" -#include "customtrackview.h" -#include "dialogs/profilesdialog.h" -#include "doc/docundostack.hpp" -#include "doc/kdenlivedoc.h" -#include "effectslist/initeffects.h" -#include "headertrack.h" -#include "kdenlivesettings.h" -#include "mainwindow.h" -#include "managers/previewmanager.h" -#include "managers/trimmanager.h" -#include "mltcontroller/clipcontroller.h" -#include "mltcontroller/effectscontroller.h" -#include "project/clipmanager.h" -#include "renderer.h" -#include "timelinecommands.h" -#include "track.h" -#include "transition.h" -#include "transitionhandler.h" -#include "utils/KoIconUtils.h" - -#include -#include -#include - -#include -#include -#include - -ScrollEventEater::ScrollEventEater(QObject *parent) - : QObject(parent) -{ -} - -bool ScrollEventEater::eventFilter(QObject *obj, QEvent *event) -{ - if (event->type() == QEvent::MouseButtonPress) { - QWidget *parent = (QWidget *)obj; - if (parent) { - parent->setFocus(); - } - return QObject::eventFilter(obj, event); - } - return QObject::eventFilter(obj, event); -} - -Timeline::Timeline(KdenliveDoc *doc, const QList &actions, const QList &rulerActions, bool *ok, QWidget *parent) - : QWidget(parent) - , multitrackView(false) - , videoTarget(-1) - , audioTarget(-1) - , m_hasOverlayTrack(false) - , m_overlayTrack(nullptr) - , m_scale(1.0) - , m_doc(doc) - , m_verticalZoom(1) - , m_timelinePreview(nullptr) - , m_usePreview(false) -{ - m_trackActions << actions; - setupUi(this); - splitter->setStretchFactor(1, 2); - connect(splitter, &QSplitter::splitterMoved, this, &Timeline::storeHeaderSize); - m_scene = new CustomTrackScene(this); - m_trackview = new CustomTrackView(doc, this, m_scene, parent); - setFocusProxy(m_trackview); - /*if (m_doc->setSceneList() == -1) { - *ok = false; - } else { - *ok = true; - }*/ - Mlt::Service s(m_doc->renderer()->getProducer()->parent().get_service()); - m_tractor = new Mlt::Tractor(s); - - // TODO: The following lines allow to add an overlay subtitle from an ASS subtitle file - /*Mlt::Filter f(*(s.profile()), "avfilter.ass"); - f.set("av.f", "/path/to/test.ass"); - f.set("in", 500); - m_tractor->attach(f);*/ - - m_ruler = new CustomRuler(doc->timecode(), rulerActions, m_trackview); - connect(m_ruler, &CustomRuler::zoneMoved, this, &Timeline::zoneMoved); - connect(m_ruler, &CustomRuler::adjustZoom, this, &Timeline::setZoom); - connect(m_ruler, &CustomRuler::mousePosition, this, &Timeline::mousePosition); - connect(m_ruler, SIGNAL(seekCursorPos(int)), m_doc->renderer(), SLOT(seek(int)), Qt::QueuedConnection); - connect(m_ruler, &CustomRuler::resizeRuler, this, &Timeline::resizeRuler, Qt::DirectConnection); - auto *layout = new QHBoxLayout; - layout->setContentsMargins(m_trackview->frameWidth(), 0, 0, 0); - layout->setSpacing(0); - ruler_frame->setLayout(layout); - ruler_frame->setFixedHeight(m_ruler->height()); - layout->addWidget(m_ruler); - - auto *sizeLayout = new QHBoxLayout; - sizeLayout->setContentsMargins(0, 0, 0, 0); - sizeLayout->setSpacing(0); - size_frame->setLayout(sizeLayout); - size_frame->setFixedHeight(m_ruler->height()); - - auto *butSmall = new QToolButton(this); - butSmall->setIcon(KoIconUtils::themedIcon(QStringLiteral("kdenlive-zoom-small"))); - butSmall->setToolTip(i18n("Smaller tracks")); - butSmall->setAutoRaise(true); - connect(butSmall, &QAbstractButton::clicked, this, &Timeline::slotVerticalZoomDown); - sizeLayout->addWidget(butSmall); - - auto *butLarge = new QToolButton(this); - butLarge->setIcon(KoIconUtils::themedIcon(QStringLiteral("kdenlive-zoom-large"))); - butLarge->setToolTip(i18n("Bigger tracks")); - butLarge->setAutoRaise(true); - connect(butLarge, &QAbstractButton::clicked, this, &Timeline::slotVerticalZoomUp); - sizeLayout->addWidget(butLarge); - - auto *enableZone = new QToolButton(this); - KDualAction *ac = (KDualAction *)m_doc->getAction(QStringLiteral("use_timeline_zone_in_edit")); - enableZone->setAutoRaise(true); - ac->setActive(KdenliveSettings::useTimelineZoneToEdit()); - enableZone->setDefaultAction(ac); - connect(ac, &KDualAction::activeChangedByUser, this, &Timeline::slotEnableZone); - sizeLayout->addWidget(enableZone); - - auto *tracksLayout = new QHBoxLayout; - tracksLayout->setContentsMargins(0, 0, 0, 0); - tracksLayout->setSpacing(0); - tracks_frame->setLayout(tracksLayout); - headers_area->setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - headers_area->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); - auto *leventEater = new ScrollEventEater(this); - headers_area->installEventFilter(leventEater); - - auto *headersLayout = new QVBoxLayout; - headersLayout->setContentsMargins(0, m_trackview->frameWidth(), 0, 0); - headersLayout->setSpacing(0); - headers_container->setLayout(headersLayout); - connect(headers_area->verticalScrollBar(), &QAbstractSlider::valueChanged, m_trackview->verticalScrollBar(), &QAbstractSlider::setValue); - - tracksLayout->addWidget(m_trackview); - connect(m_trackview->verticalScrollBar(), &QAbstractSlider::valueChanged, headers_area->verticalScrollBar(), &QAbstractSlider::setValue); - connect(m_trackview, &CustomTrackView::tracksChanged, this, &Timeline::slotReloadTracks); - connect(m_trackview, &CustomTrackView::updateTrackHeaders, this, &Timeline::slotRepaintTracks); - connect(m_trackview, SIGNAL(showTrackEffects(int, TrackInfo)), this, SIGNAL(showTrackEffects(int, TrackInfo))); - connect(m_trackview, &CustomTrackView::updateTrackEffectState, this, &Timeline::slotUpdateTrackEffectState); - transitionHandler = new TransitionHandler(m_tractor); - connect(m_trackview, &CustomTrackView::cursorMoved, m_ruler, &CustomRuler::slotCursorMoved); - connect(m_trackview, &CustomTrackView::updateRuler, m_ruler, &CustomRuler::updateRuler, Qt::DirectConnection); - - connect(m_trackview->horizontalScrollBar(), &QAbstractSlider::valueChanged, m_ruler, &CustomRuler::slotMoveRuler); - connect(m_trackview->horizontalScrollBar(), &QAbstractSlider::rangeChanged, this, &Timeline::slotUpdateVerticalScroll); - connect(m_trackview, &CustomTrackView::mousePosition, this, &Timeline::mousePosition); - m_disablePreview = m_doc->getAction(QStringLiteral("disable_preview")); - connect(m_disablePreview, &QAction::triggered, this, &Timeline::disablePreview); - m_disablePreview->setEnabled(false); - m_trackview->initTools(); - //splitter->restoreState(QByteArray::fromBase64(KdenliveSettings::timelineheaderwidth().toUtf8())); - QAction *previewRender = m_doc->getAction(QStringLiteral("prerender_timeline_zone")); - previewRender->setEnabled(true); -} - -Timeline::~Timeline() -{ - if (m_timelinePreview) { - delete m_timelinePreview; - } - delete m_ruler; - delete m_trackview; - delete m_scene; - delete transitionHandler; - delete m_tractor; - qDeleteAll<>(m_tracks); - m_tracks.clear(); -} - -void Timeline::resizeRuler(int height) -{ - ruler_frame->setFixedHeight(height); - size_frame->setFixedHeight(height); -} - -void Timeline::loadTimeline() -{ - parseDocument(m_doc->toXml()); - m_trackview->slotUpdateAllThumbs(); - slotChangeZoom(m_doc->zoom().x(), m_doc->zoom().y()); - headers_area->verticalScrollBar()->setRange(0, m_trackview->verticalScrollBar()->maximum()); - m_trackview->slotSelectTrack(m_trackview->getNextVideoTrack(1)); - slotSetZone(m_doc->zone(), false); - loadPreviewRender(); -} - -QMap Timeline::documentProperties() -{ - QMap props = m_doc->documentProperties(); - props.insert(QStringLiteral("audiotargettrack"), QString::number(audioTarget)); - props.insert(QStringLiteral("videotargettrack"), QString::number(videoTarget)); - QPair chunks = m_ruler->previewChunks(); - props.insert(QStringLiteral("previewchunks"), chunks.first.join(QLatin1Char(','))); - props.insert(QStringLiteral("dirtypreviewchunks"), chunks.second.join(QLatin1Char(','))); - props.insert(QStringLiteral("disablepreview"), QString::number((int)m_disablePreview->isChecked())); - return props; -} - -Track *Timeline::track(int i) -{ - if (i < 0 || i >= m_tracks.count()) { - return nullptr; - } - return m_tracks.at(i); -} - -int Timeline::tracksCount() const -{ - return m_tractor->count() - static_cast(m_hasOverlayTrack) - static_cast(m_usePreview); -} - -int Timeline::visibleTracksCount() const -{ - return m_tractor->count() - 1 - static_cast(m_hasOverlayTrack) - static_cast(m_usePreview); -} - -int Timeline::duration() const -{ - return m_trackview->duration(); -} - -bool Timeline::checkProjectAudio() -{ - bool hasAudio = false; - int max = m_tracks.count(); - // Ignore black background track, start at one - for (int i = 1; i < max; i++) { - Track *sourceTrack = track(i); - QScopedPointer track(m_tractor->track(i)); - int state = track->get_int("hide"); - if ((sourceTrack != nullptr) && sourceTrack->hasAudio() && ((state & 2) == 0)) { - hasAudio = true; - break; - } - } - return hasAudio; -} - -int Timeline::inPoint() const -{ - return m_ruler->inPoint(); -} - -int Timeline::outPoint() const -{ - return m_ruler->outPoint(); -} - -void Timeline::slotSetZone(const QPoint &p, bool updateDocumentProperties) -{ - m_ruler->setZone(p); - if (updateDocumentProperties) { - m_doc->setZone(p.x(), p.y()); - } -} - -void Timeline::setDuration(int dur) -{ - m_trackview->setDuration(dur); - m_ruler->setDuration(dur); -} - -int Timeline::getTracks() -{ - int duration = 1; - qDeleteAll<>(m_tracks); - m_tracks.clear(); - QVBoxLayout *headerLayout = qobject_cast(headers_container->layout()); - QLayoutItem *child; - while ((child = headerLayout->takeAt(0)) != nullptr) { - delete child; - } - int clipsCount = 0; - for (int i = 0; i < m_tractor->count(); ++i) { - QScopedPointer track(m_tractor->track(i)); - QString playlist_name = track->get("id"); - if (playlist_name == QLatin1String("black_track") || playlist_name == QLatin1String("timeline_preview") || - playlist_name == QLatin1String("overlay_track")) { - continue; - } - clipsCount += track->count(); - } - emit startLoadingBin(clipsCount); - emit resetUsageCount(); - checkTrackHeight(false); - int height = KdenliveSettings::trackheight() * m_scene->scale().y() - 1; - int headerWidth = 0; - int offset = 0; - for (int i = 0; i < m_tractor->count(); ++i) { - QScopedPointer track(m_tractor->track(i)); - QString playlist_name = track->get("id"); - if (playlist_name == QLatin1String("playlistmain") || playlist_name == QLatin1String("timeline_preview") || - playlist_name == QLatin1String("overlay_track")) { - continue; - } - bool isBackgroundBlackTrack = playlist_name == QLatin1String("black_track"); - // check track effects - Mlt::Playlist playlist(*track); - int trackduration = 0; - int audio = 0; - Track *tk = nullptr; - if (!isBackgroundBlackTrack) { - audio = playlist.get_int("kdenlive:audio_track"); - tk = new Track(i, m_trackActions, playlist, audio == 1 ? AudioTrack : VideoTrack, height, this); - m_tracks.append(tk); - trackduration = loadTrack(i, offset, playlist); - QFrame *frame = new QFrame(headers_container); - frame->setFrameStyle(QFrame::HLine); - frame->setFixedHeight(1); - headerLayout->insertWidget(0, frame); - } else { - // Black track - tk = new Track(i, m_trackActions, playlist, audio == 1 ? AudioTrack : VideoTrack, 0, this); - m_tracks.append(tk); - } - offset += track->count(); - - if (!isBackgroundBlackTrack) { - int currentWidth = tk->trackHeader->minimumWidth(); - if (currentWidth > headerWidth) { - headerWidth = currentWidth; - } - headerLayout->insertWidget(0, tk->trackHeader); - if (trackduration > duration) { - duration = trackduration; - } - tk->trackHeader->setSelectedIndex(m_trackview->selectedTrack()); - connect(tk->trackHeader, &HeaderTrack::switchTrackVideo, this, &Timeline::switchTrackVideo); - connect(tk->trackHeader, &HeaderTrack::switchTrackAudio, this, &Timeline::switchTrackAudio); - connect(tk->trackHeader, SIGNAL(switchTrackLock(int, bool)), m_trackview, SLOT(slotSwitchTrackLock(int, bool))); - connect(tk->trackHeader, &HeaderTrack::selectTrack, m_trackview, &CustomTrackView::slotSelectTrack); - connect(tk->trackHeader, SIGNAL(renameTrack(int, QString)), this, SLOT(slotRenameTrack(int, QString))); - connect(tk->trackHeader, &HeaderTrack::configTrack, this, &Timeline::configTrack); - connect(tk->trackHeader, SIGNAL(addTrackEffect(QDomElement, int)), m_trackview, SLOT(slotAddTrackEffect(QDomElement, int))); - if (playlist.filter_count() != 0) { - getEffects(playlist, nullptr, i); - slotUpdateTrackEffectState(i); - } - connect(tk, &Track::newTrackDuration, this, &Timeline::checkDuration, Qt::DirectConnection); - connect(tk, SIGNAL(storeSlowMotion(QString, Mlt::Producer *)), m_doc->renderer(), SLOT(storeSlowmotionProducer(QString, Mlt::Producer *))); - } - } - headers_area->setMinimumWidth(headerWidth); - if (audioTarget > -1) { - m_tracks.at(audioTarget)->trackHeader->switchTarget(true); - } - if (videoTarget > -1) { - m_tracks.at(videoTarget)->trackHeader->switchTarget(true); - } - updatePalette(); - refreshTrackActions(); - return duration; -} - -void Timeline::checkDuration() -{ - m_doc->renderer()->mltCheckLength(m_tractor); -} - -void Timeline::getTransitions() -{ - int compositeMode = 0; - double fps = pCore->getCurrentFps(); - mlt_service service = mlt_service_get_producer(m_tractor->get_service()); - QScopedPointer field(m_tractor->field()); - while (service != nullptr) { - Mlt::Properties prop(MLT_SERVICE_PROPERTIES(service)); - if (QString(prop.get("mlt_type")) != QLatin1String("transition")) { - break; - } - // skip automatic mix - if (prop.get_int("internal_added") == 237) { - QString trans = prop.get("mlt_service"); - if (trans == QLatin1String("qtblend") || trans == QLatin1String("movit.overlay") || trans == QLatin1String("frei0r.cairoblend")) { - compositeMode = 2; - } else if (trans == QLatin1String("composite")) { - compositeMode = 1; - } - service = mlt_service_producer(service); - continue; - } - - int a_track = prop.get_int("a_track"); - int b_track = prop.get_int("b_track"); - ItemInfo transitionInfo; - transitionInfo.startPos = GenTime(prop.get_int("in"), fps); - transitionInfo.endPos = GenTime(prop.get_int("out") + 1, fps); - transitionInfo.track = b_track; - // When adding composite transition, check if it is a wipe transition - if (prop.get("kdenlive_id") == nullptr && QString(prop.get("mlt_service")) == QLatin1String("composite") && isSlide(prop.get("geometry"))) { - prop.set("kdenlive_id", "slide"); - } - QDomElement base = MainWindow::transitions.getEffectByTag(prop.get("mlt_service"), prop.get("kdenlive_id")).cloneNode().toElement(); - // check invalid parameters - if (a_track > m_tractor->count() - 1) { - m_documentErrors.append(i18n("Transition %1 had an invalid track: %2 > %3", prop.get("id"), a_track, m_tractor->count() - 1) + QLatin1Char('\n')); - prop.set("a_track", m_tractor->count() - 1); - } - if (b_track > m_tractor->count() - 1) { - m_documentErrors.append(i18n("Transition %1 had an invalid track: %2 > %3", prop.get("id"), b_track, m_tractor->count() - 1) + QLatin1Char('\n')); - prop.set("b_track", m_tractor->count() - 1); - } - if (a_track == b_track || b_track <= 0 || transitionInfo.startPos >= transitionInfo.endPos || base.isNull() - //|| !m_trackview->canBePastedTo(transitionInfo, TransitionWidget) - ) { - // invalid transition, remove it - m_documentErrors.append(i18n("Removed invalid transition: %1", prop.get("id")) + QLatin1Char('\n')); - mlt_service broken = service; - service = mlt_service_producer(service); - mlt_field_disconnect_service(field->get_field(), broken); - continue; - } else { - // Check there is no other transition at that place - double startY = m_trackview->getPositionFromTrack(transitionInfo.track) + 1 + KdenliveSettings::trackheight() / 2; - QRectF r(transitionInfo.startPos.frames(fps), startY, (transitionInfo.endPos - transitionInfo.startPos).frames(fps), - KdenliveSettings::trackheight() / 2); - QList selection = m_scene->items(r); - bool transitionAccepted = true; - for (int i = 0; i < selection.count(); ++i) { - if (selection.at(i)->type() == TransitionWidget) { - transitionAccepted = false; - break; - } - } - if (!transitionAccepted) { - m_documentErrors.append(i18n("Removed invalid transition: %1", prop.get("id")) + QLatin1Char('\n')); - mlt_service broken = service; - service = mlt_service_producer(service); - mlt_field_disconnect_service(field->get_field(), broken); - continue; - } else { - QDomNodeList params = base.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - QString paramName = e.hasAttribute(QStringLiteral("tag")) ? e.attribute(QStringLiteral("tag")) : e.attribute(QStringLiteral("name")); - QString value = prop.get(paramName.toUtf8().constData()); - // if transition parameter has an "optional" attribute, it means that it can contain an empty value - if (value.isEmpty() && !e.hasAttribute(QStringLiteral("optional"))) { - continue; - } - if (e.hasAttribute(QStringLiteral("factor")) || e.hasAttribute(QStringLiteral("offset"))) { - adjustDouble(e, value); - } else { - e.setAttribute(QStringLiteral("value"), value); - } - } - Transition *tr = new Transition(transitionInfo, a_track, fps, base, QString(prop.get("automatic")) == QLatin1String("1")); - connect(tr, &AbstractClipItem::selectItem, m_trackview, &CustomTrackView::slotSelectItem); - tr->setPos(transitionInfo.startPos.frames(fps), - KdenliveSettings::trackheight() * (visibleTracksCount() - transitionInfo.track) + 1 + tr->itemOffset()); - if (QString(prop.get("force_track")) == QLatin1String("1")) { - tr->setForcedTrack(true, a_track); - } - if (isTrackLocked(b_track)) { - tr->setItemLocked(true); - } - m_scene->addItem(tr); - } - service = mlt_service_producer(service); - } - } - m_doc->updateCompositionMode(compositeMode); -} - -// static -bool Timeline::isSlide(QString geometry) -{ - if (geometry.count(QLatin1Char(';')) != 1) { - return false; - } - - geometry.remove(QLatin1Char('%'), Qt::CaseInsensitive); - geometry.replace(QLatin1Char('x'), QLatin1Char(':'), Qt::CaseInsensitive); - geometry.replace(QLatin1Char(','), QLatin1Char(':'), Qt::CaseInsensitive); - geometry.replace(QLatin1Char('/'), QLatin1Char(':'), Qt::CaseInsensitive); - - QString start = geometry.section(QLatin1Char('='), 0, 0).section(QLatin1Char(':'), 0, -2) + QLatin1Char(':'); - start.append(geometry.section(QLatin1Char('='), 1, 1).section(QLatin1Char(':'), 0, -2)); - QStringList numbers = start.split(QLatin1Char(':'), QString::SkipEmptyParts); - for (int i = 0; i < numbers.size(); ++i) { - int checkNumber = qAbs(numbers.at(i).toInt()); - if (checkNumber != 0 && checkNumber != 100) { - return false; - } - } - return true; -} - -void Timeline::adjustDouble(QDomElement &e, const QString &value) -{ - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - QString factor = e.attribute(QStringLiteral("factor"), QStringLiteral("1")); - double offset = locale.toDouble(e.attribute(QStringLiteral("offset"), QStringLiteral("0"))); - double fact = 1; - if (factor.contains(QLatin1Char('%'))) { - fact = EffectsController::getStringEval(factor); - } else { - fact = locale.toDouble(factor); - } - QString type = e.attribute(QStringLiteral("type")); - if (type == QLatin1String("double") || type == QLatin1String("constant")) { - double val = locale.toDouble(value); - e.setAttribute(QStringLiteral("value"), locale.toString(offset + val * fact)); - } else if (type == QLatin1String("simplekeyframe")) { - QStringList keys = value.split(QLatin1Char(';')); - for (int j = 0; j < keys.count(); ++j) { - QString pos = keys.at(j).section(QLatin1Char('='), 0, 0); - double val = locale.toDouble(keys.at(j).section(QLatin1Char('='), 1, 1)) * fact + offset; - keys[j] = pos + QLatin1Char('=') + locale.toString(val); - } - e.setAttribute(QStringLiteral("value"), keys.join(QLatin1Char(';'))); - } else { - e.setAttribute(QStringLiteral("value"), value); - } -} - -void Timeline::parseDocument(const QDomDocument &doc) -{ - // int cursorPos = 0; - m_documentErrors.clear(); - m_replacementProducerIds.clear(); - - // parse project tracks - QDomElement mlt = doc.firstChildElement(QStringLiteral("mlt")); - m_trackview->setDuration(getTracks()); - getTransitions(); - - // Rebuild groups - QDomDocument groupsDoc; - groupsDoc.setContent(m_doc->renderer()->getBinProperty(QStringLiteral("kdenlive:clipgroups"))); - QDomNodeList groups = groupsDoc.elementsByTagName(QStringLiteral("group")); - m_trackview->loadGroups(groups); - - // Load custom effects - QDomDocument effectsDoc; - effectsDoc.setContent(m_doc->renderer()->getBinProperty(QStringLiteral("kdenlive:customeffects"))); - QDomNodeList effects = effectsDoc.elementsByTagName(QStringLiteral("effect")); - if (!effects.isEmpty()) { - m_doc->saveCustomEffects(effects); - } - - if (!m_documentErrors.isNull()) { - KMessageBox::sorry(this, m_documentErrors); - } - if (mlt.hasAttribute(QStringLiteral("upgraded")) || mlt.hasAttribute(QStringLiteral("modified"))) { - // Our document was upgraded, create a backup copy just in case - QString baseFile = m_doc->url().toLocalFile().section(QStringLiteral(".kdenlive"), 0, 0); - int ct = 0; - QString backupFile = baseFile + QStringLiteral("_backup") + QString::number(ct) + QStringLiteral(".kdenlive"); - while (QFile::exists(backupFile)) { - ct++; - backupFile = baseFile + QStringLiteral("_backup") + QString::number(ct) + QStringLiteral(".kdenlive"); - } - QString message; - if (mlt.hasAttribute(QStringLiteral("upgraded"))) { - message = i18n("Your project file was upgraded to the latest Kdenlive document version.\nTo make sure you don't lose data, a backup copy called %1 " - "was created.", - backupFile); - } else { - message = i18n("Your project file was modified by Kdenlive.\nTo make sure you don't lose data, a backup copy called %1 was created.", backupFile); - } - - KIO::FileCopyJob *copyjob = KIO::file_copy(m_doc->url(), QUrl::fromLocalFile(backupFile)); - if (copyjob->exec()) { - KMessageBox::information(this, message); - } else { - KMessageBox::information( - this, i18n("Your project file was upgraded to the latest Kdenlive document version, but it was not possible to create the backup copy %1.", - backupFile)); - } - } -} - -void Timeline::slotDeleteClip(const QString &clipId, QUndoCommand *deleteCommand) -{ - m_trackview->deleteClip(clipId, deleteCommand); -} - -void Timeline::setCursorPos(int pos) -{ - m_trackview->setCursorPos(pos); -} - -void Timeline::moveCursorPos(int pos) -{ - m_trackview->setCursorPos(pos); -} - -void Timeline::slotChangeZoom(int horizontal, int vertical, bool zoomOnMouse) -{ - m_ruler->setPixelPerMark(horizontal); - m_scale = (double)m_trackview->getFrameWidth() / m_ruler->comboScale[horizontal]; - - if (vertical == -1) { - // user called zoom - m_doc->setZoom(horizontal, m_verticalZoom); - m_trackview->setScale(m_scale, m_scene->scale().y(), zoomOnMouse); - } else { - m_verticalZoom = vertical; - if (m_verticalZoom == 0) { - m_trackview->setScale(m_scale, 0.5); - } else { - m_trackview->setScale(m_scale, m_verticalZoom); - } - adjustTrackHeaders(); - } -} - -int Timeline::fitZoom() const -{ - int zoom = (int)((duration() + 20 / m_scale) * m_trackview->getFrameWidth() / m_trackview->width()); - int i; - for (i = 0; i < 13; ++i) - if (m_ruler->comboScale[i] > zoom) { - break; - } - return i; -} - -KdenliveDoc *Timeline::document() -{ - return m_doc; -} - -void Timeline::refresh() -{ - m_trackview->viewport()->update(); -} - -void Timeline::slotRepaintTracks() -{ - for (int i = 1; i < m_tracks.count(); i++) { - m_tracks.at(i)->trackHeader->setSelectedIndex(m_trackview->selectedTrack()); - } -} - -void Timeline::blockTrackSignals(bool block) -{ - for (int i = 1; i < m_tracks.count(); i++) { - m_tracks.at(i)->blockSignals(block); - } -} - -void Timeline::slotReloadTracks() -{ - emit updateTracksInfo(); -} - -TrackInfo Timeline::getTrackInfo(int ix) -{ - if (ix < 0 || ix > m_tracks.count()) { - qCWarning(KDENLIVE_LOG) << "/// ARGH, requested info for track: " << ix << " - MAX is: " << m_tracks.count(); - // Let it crash to find wrong calls - TrackInfo info; - return info; - } - Track *tk = track(ix); - if (tk == nullptr) { - qCWarning(KDENLIVE_LOG) << "/// ARGH, requesting nullptr track: " << ix << " - MAX is: " << m_tracks.count(); - // Let it crash to find wrong calls - TrackInfo info; - return info; - } - return tk->info(); -} - -bool Timeline::isLastClip(const ItemInfo &info) -{ - Track *tk = track(info.track); - if (tk == nullptr) { - return true; - } - return tk->isLastClip(info.endPos.seconds()); -} - -void Timeline::setTrackInfo(int ix, const TrackInfo &info) -{ - if (ix < 0 || ix > m_tracks.count()) { - qCWarning(KDENLIVE_LOG) << "Set Track effect outisde of range"; - return; - } - Track *tk = track(ix); - tk->setInfo(info); -} - -QList Timeline::getTracksInfo() -{ - QList tracks; - for (int i = 0; i < tracksCount(); i++) { - tracks << track(i)->info(); - } - return tracks; -} - -QStringList Timeline::getTrackNames() -{ - QStringList trackNames; - for (int i = 1; i < tracksCount(); i++) { - trackNames << track(i)->info().trackName; - } - return trackNames; -} - -void Timeline::lockTrack(int ix, bool lock) -{ - Track *tk = track(ix); - if (tk == nullptr) { - qCWarning(KDENLIVE_LOG) << "Set Track effect outisde of range: " << ix; - return; - } - tk->lockTrack(lock); -} - -bool Timeline::isTrackLocked(int ix) -{ - Track *tk = track(ix); - if (tk == nullptr) { - qCWarning(KDENLIVE_LOG) << "Set Track effect outisde of range: " << ix; - return false; - } - int locked = tk->getIntProperty(QStringLiteral("kdenlive:locked_track")); - return locked == 1; -} - -void Timeline::updateTrackState(int ix, int state) -{ - int currentState = 0; - QScopedPointer track(m_tractor->track(ix)); - currentState = track->get_int("hide"); - if (state == currentState) { - return; - } - if (state == 0) { - // Show all - if ((currentState & 1) != 0) { - doSwitchTrackVideo(ix, false); - } - if ((currentState & 2) != 0) { - doSwitchTrackAudio(ix, false); - } - } else if (state == 1) { - // Mute video - if ((currentState & 2) != 0) { - doSwitchTrackAudio(ix, false); - } - doSwitchTrackVideo(ix, true); - } else if (state == 2) { - // Mute audio - if ((currentState & 1) != 0) { - doSwitchTrackVideo(ix, false); - } - doSwitchTrackAudio(ix, true); - } else { - doSwitchTrackVideo(ix, true); - doSwitchTrackAudio(ix, true); - } -} - -void Timeline::switchTrackVideo(int ix, bool hide) -{ - QUndoCommand *trackState = new ChangeTrackStateCommand(this, ix, false, true, false, hide); - m_doc->commandStack()->push(trackState); -} - -void Timeline::switchTrackAudio(int ix, bool hide) -{ - QUndoCommand *trackState = new ChangeTrackStateCommand(this, ix, true, false, hide, false); - m_doc->commandStack()->push(trackState); -} - -void Timeline::doSwitchTrackVideo(int ix, bool hide) -{ - Track *tk = track(ix); - if (tk == nullptr) { - qCWarning(KDENLIVE_LOG) << "Set Track effect outisde of range: " << ix; - return; - } - int state = tk->state(); - if (hide && ((state & 1) != 0)) { - // Video is already muted - return; - } - tk->trackHeader->setVideoMute(hide); - int newstate = 0; - if (hide) { - if ((state & 2) != 0) { - newstate = 3; - } else { - newstate = 1; - } - } else { - if ((state & 2) != 0) { - newstate = 2; - } else { - newstate = 0; - } - } - if (newstate > 0) { - // hide - invalidateTrack(ix); - } - tk->setState(newstate); - if (newstate == 0) { - // unhide - invalidateTrack(ix); - } - refreshTractor(); - m_doc->renderer()->doRefresh(); -} - -void Timeline::refreshTransitions() -{ - switchComposite(-1); -} - -void Timeline::refreshTractor() -{ - m_tractor->multitrack()->refresh(); - m_tractor->refresh(); -} - -void Timeline::doSwitchTrackAudio(int ix, bool mute) -{ - Track *tk = track(ix); - if (tk == nullptr) { - qCWarning(KDENLIVE_LOG) << "Set Track effect outisde of range: " << ix; - return; - } - int state = tk->state(); - if (mute && ((state & 2) != 0)) { - // audio is already muted - return; - } - tk->trackHeader->setAudioMute(mute); - int newstate; - if (mute) { - if ((state & 1) != 0) { - newstate = 3; - } else { - newstate = 2; - } - } else if ((state & 1) != 0) { - newstate = 1; - } else { - newstate = 0; - } - tk->setState(newstate); - m_tractor->multitrack()->refresh(); - m_tractor->refresh(); -} - -int Timeline::getLowestVideoTrack() -{ - for (int i = 1; i < m_tractor->count(); ++i) { - QScopedPointer track(m_tractor->track(i)); - Mlt::Playlist playlist(*track); - if (playlist.get_int("kdenlive:audio_track") != 1) { - return i; - } - } - return -1; -} - -void Timeline::updatePalette() -{ - headers_container->setStyleSheet(QString()); - setPalette(qApp->palette()); - QPalette p = qApp->palette(); - KColorScheme scheme(p.currentColorGroup(), KColorScheme::View, KSharedConfig::openConfig(KdenliveSettings::colortheme())); - QColor col = scheme.background().color(); - QColor col2 = scheme.foreground().color(); - headers_container->setStyleSheet( - QStringLiteral( - "QLineEdit { background-color: transparent;color: %1;} QLineEdit:hover{ background-color: %2;} QLineEdit:focus { background-color: %2;} ") - .arg(col2.name(), col.name())); - m_trackview->updatePalette(); - if (!m_tracks.isEmpty()) { - int ix = m_trackview->selectedTrack(); - for (int i = 0; i < m_tracks.count(); i++) { - if (m_tracks.at(i)->trackHeader) { - m_tracks.at(i)->trackHeader->refreshPalette(); - if (i == ix) { - m_tracks.at(ix)->trackHeader->setSelectedIndex(ix); - } - } - } - } - m_ruler->activateZone(); -} - -void Timeline::updateHeaders() -{ - if (!m_tracks.isEmpty()) { - for (int i = 0; i < m_tracks.count(); i++) { - if (m_tracks.at(i)->trackHeader) { - m_tracks.at(i)->trackHeader->updateLed(); - } - } - } -} - -void Timeline::refreshIcons() -{ - QList allMenus = this->findChildren(); - for (int i = 0; i < allMenus.count(); i++) { - QAction *m = allMenus.at(i); - QIcon ic = m->icon(); - if (ic.isNull() || ic.name().isEmpty()) { - continue; - } - QIcon newIcon = KoIconUtils::themedIcon(ic.name()); - m->setIcon(newIcon); - } - QList allButtons = this->findChildren(); - for (int i = 0; i < allButtons.count(); i++) { - KDualAction *m = allButtons.at(i); - QIcon ic = m->activeIcon(); - if (ic.isNull() || ic.name().isEmpty()) { - continue; - } - QIcon newIcon = KoIconUtils::themedIcon(ic.name()); - m->setActiveIcon(newIcon); - ic = m->inactiveIcon(); - if (ic.isNull() || ic.name().isEmpty()) { - continue; - } - newIcon = KoIconUtils::themedIcon(ic.name()); - m->setInactiveIcon(newIcon); - } -} - -void Timeline::adjustTrackHeaders() -{ - if (m_tracks.isEmpty()) { - return; - } - int height = KdenliveSettings::trackheight() * m_scene->scale().y() - 1; - for (int i = 1; i < m_tracks.count(); i++) { - m_tracks.at(i)->trackHeader->adjustSize(height); - } -} - -void Timeline::reloadTrack(int ix, int start, int end) -{ - // Get playlist - Mlt::Playlist pl = m_tracks.at(ix)->playlist(); - if (end == -1) { - end = pl.get_length(); - } - // Remove current clips - int startIndex = pl.get_clip_index_at(start); - int endIndex = pl.get_clip_index_at(end); - double startY = m_trackview->getPositionFromTrack(ix) + 2; - QRectF r(start, startY, end - start, 2); - QList selection = m_scene->items(r); - QList toDelete; - for (int i = 0; i < selection.count(); i++) { - if (selection.at(i)->type() == AVWidget) { - toDelete << selection.at(i); - } - } - qDeleteAll(toDelete); - // Reload items - loadTrack(ix, 0, pl, startIndex, endIndex, false); -} - -void Timeline::reloadTrack(const ItemInfo &info, bool includeLastFrame) -{ - // Get playlist - if (!info.isValid()) { - return; - } - Mlt::Playlist pl = m_tracks.at(info.track)->playlist(); - // Remove current clips - int startIndex = pl.get_clip_index_at(info.startPos.frames(pCore->getCurrentFps())); - int endIndex = pl.get_clip_index_at(info.endPos.frames(pCore->getCurrentFps())) - (includeLastFrame ? 0 : 1); - // Reload items - loadTrack(info.track, 0, pl, startIndex, endIndex, false); -} - -int Timeline::loadTrack(int ix, int offset, Mlt::Playlist &playlist, int start, int end, bool updateReferences) -{ - // parse track - double fps = pCore->getCurrentFps(); - if (end == -1) { - end = playlist.count(); - } - bool locked = playlist.get_int("kdenlive:locked_track") == 1; - for (int i = start; i <= end; ++i) { - emit loadingBin(offset + i + 1); - if (playlist.is_blank(i)) { - continue; - } - // TODO: playlist::clip_info(i, info) crashes on MLT < 6.6.0, so use variant until MLT 6.6.x is required - QScopedPointer info(playlist.clip_info(i)); - Mlt::Producer *clip = info->cut; - // Found a clip - QString idString = info->producer->get("id"); - if (info->frame_in > info->frame_out || m_invalidProducers.contains(idString)) { - QString trackName = playlist.get("kdenlive:track_name"); - m_documentErrors.append(i18n("Invalid clip removed from track %1 at %2\n", trackName.isEmpty() ? QString::number(ix) : trackName, info->start)); - playlist.remove(i); - --i; - continue; - } - QString id = idString; - Track::SlowmoInfo slowInfo; - slowInfo.speed = 1.0; - slowInfo.strobe = 1; - slowInfo.state = PlaylistState::Original; - bool hasSpeedEffect = false; - if (idString.endsWith(QLatin1String("_video"))) { - // Video only producer, store it in BinController - m_doc->renderer()->loadExtraProducer(idString, new Mlt::Producer(clip->parent())); - } - if (idString.startsWith(QLatin1String("slowmotion"))) { - hasSpeedEffect = true; - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - id = idString.section(QLatin1Char(':'), 1, 1); - slowInfo.speed = locale.toDouble(idString.section(QLatin1Char(':'), 2, 2)); - slowInfo.strobe = idString.section(QLatin1Char(':'), 3, 3).toInt(); - if (slowInfo.strobe == 0) { - slowInfo.strobe = 1; - } - slowInfo.state = (PlaylistState::ClipState)idString.section(QLatin1Char(':'), 4, 4).toInt(); - // Slowmotion producer, store it for reuse - auto *parentProd = new Mlt::Producer(clip->parent()); - QString url = parentProd->get("warp_resource"); - if (!m_doc->renderer()->storeSlowmotionProducer(slowInfo.toString(locale) + url, parentProd)) { - delete parentProd; - } - } - id = id.section(QLatin1Char('_'), 0, 0); - std::shared_ptr binclip = m_doc->getBinClip(id); - PlaylistState::ClipState originalState = PlaylistState::Original; - if (!binclip) { - // Is this a disabled clip - id = info->producer->get("kdenlive:binid"); - binclip = m_doc->getBinClip(id); - originalState = (PlaylistState::ClipState)info->producer->get_int("kdenlive:clipstate"); - } - if (!binclip) { - // Warning, unknown clip found, timeline corruption!! - // TODO: fix this - qCDebug(KDENLIVE_LOG) << "* * * * *UNKNOWN CLIP, WE ARE DEAD: " << id; - continue; - } - if (updateReferences) { - binclip->addRef(); - } - ItemInfo clipinfo; - clipinfo.startPos = GenTime(info->start, fps); - clipinfo.endPos = GenTime(info->start + info->frame_count, fps); - clipinfo.cropStart = GenTime(info->frame_in, fps); - clipinfo.cropDuration = GenTime(info->frame_count, fps); - clipinfo.track = ix; - // qCDebug(KDENLIVE_LOG)<<"// Loading clip: "<getFrameWidth(), true); - connect(item, &AbstractClipItem::selectItem, m_trackview, &CustomTrackView::slotSelectItem); - item->setPos(clipinfo.startPos.frames(fps), KdenliveSettings::trackheight() * (visibleTracksCount() - clipinfo.track) + 1 + item->itemOffset()); - // qCDebug(KDENLIVE_LOG)<<" * * Loaded clip on tk: "<updateState(idString, info->producer->get_int("audio_index"), info->producer->get_int("video_index"), originalState); - m_scene->addItem(item); - if (locked) { - item->setItemLocked(true); - } - if (hasSpeedEffect) { - QDomElement speedeffect = MainWindow::videoEffects.getEffectByTag(QString(), QStringLiteral("speed")).cloneNode().toElement(); - EffectsList::setParameter(speedeffect, QStringLiteral("speed"), QString::number((int)(100 * slowInfo.speed + 0.5))); - EffectsList::setParameter(speedeffect, QStringLiteral("strobe"), QString::number(slowInfo.strobe)); - item->addEffect(speedeffect, false); - } - // parse clip effects - getEffects(*clip, item); - } - return playlist.get_length(); -} - -void Timeline::loadGuides(const QMap &guidesData) -{ - QMapIterator i(guidesData); - while (i.hasNext()) { - i.next(); - // Guide positions are stored in seconds. we need to make sure that the time matches a frame - const GenTime pos = GenTime(GenTime(i.key()).frames(pCore->getCurrentFps()), pCore->getCurrentFps()); - m_trackview->addGuide(pos, i.value(), true); - } -} - -void Timeline::getEffects(Mlt::Service &service, ClipItem *clip, int track) -{ - int effectNb = clip == nullptr ? 0 : clip->effectsCount(); - for (int ix = 0; ix < service.filter_count(); ++ix) { - QScopedPointer effect(service.filter(ix)); - QDomElement clipeffect = getEffectByTag(effect->get("tag"), effect->get("kdenlive_id")); - if (clipeffect.isNull()) { - m_documentErrors.append(i18n("Effect %1:%2 not found in MLT, it was removed from this project\n", effect->get("tag"), effect->get("kdenlive_id"))); - service.detach(*effect); - --ix; - continue; - } - effectNb++; - QDomElement currenteffect = clipeffect.cloneNode().toElement(); - currenteffect.setAttribute(QStringLiteral("kdenlive_ix"), QString::number(effectNb)); - currenteffect.setAttribute(QStringLiteral("kdenlive_info"), effect->get("kdenlive_info")); - currenteffect.setAttribute(QStringLiteral("disable"), effect->get("disable")); - QDomNodeList clipeffectparams = currenteffect.childNodes(); - - QDomNodeList params = currenteffect.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - if (e.attribute(QStringLiteral("type")) == QLatin1String("keyframe")) { - e.setAttribute(QStringLiteral("keyframes"), getKeyframes(service, ix, e)); - } else { - setParam(e, effect->get(e.attribute(QStringLiteral("name")).toUtf8().constData())); - } - } - - if (effect->get_out() != 0) { // no keyframes but in/out points - // EffectsList::setParameter(currenteffect, QStringLiteral("in"), effect->get("in")); - // EffectsList::setParameter(currenteffect, QStringLiteral("out"), effect->get("out")); - currenteffect.setAttribute(QStringLiteral("in"), effect->get_in()); - currenteffect.setAttribute(QStringLiteral("out"), effect->get_out()); - } - QString sync = effect->get("kdenlive:sync_in_out"); - if (!sync.isEmpty()) { - currenteffect.setAttribute(QStringLiteral("kdenlive:sync_in_out"), sync); - } - if (QString(effect->get("tag")) == QLatin1String("region")) { - getSubfilters(effect.data(), currenteffect); - } - if (clip) { - clip->addEffect(currenteffect, false); - } else { - addTrackEffect(track, currenteffect, false); - } - } -} - -QString Timeline::getKeyframes(Mlt::Service service, int &ix, const QDomElement &e) -{ - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - QString starttag = e.attribute(QStringLiteral("starttag"), QStringLiteral("start")); - QString endtag = e.attribute(QStringLiteral("endtag"), QStringLiteral("end")); - double fact, offset = locale.toDouble(e.attribute(QStringLiteral("offset"), QStringLiteral("0"))); - QString factor = e.attribute(QStringLiteral("factor"), QStringLiteral("1")); - if (factor.contains(QLatin1Char('%'))) { - fact = EffectsController::getStringEval(factor); - } else { - fact = locale.toDouble(factor); - } - // retrieve keyframes - QScopedPointer effect(service.filter(ix)); - int effectNb = effect->get_int("kdenlive_ix"); - QString keyframes = QString::number(effect->get_in()) + QLatin1Char('=') + - locale.toString(offset + fact * effect->get_double(starttag.toUtf8().constData())) + QLatin1Char(';'); - for (; ix < service.filter_count(); ++ix) { - QScopedPointer eff2(service.filter(ix)); - if (eff2->get_int("kdenlive_ix") != effectNb) { - break; - } - if (eff2->get_in() < eff2->get_out()) { - keyframes.append(QString::number(eff2->get_out()) + QLatin1Char('=') + - locale.toString(offset + fact * eff2->get_double(endtag.toUtf8().constData())) + QLatin1Char(';')); - } - } - --ix; - return keyframes; -} - -void Timeline::getSubfilters(Mlt::Filter *effect, QDomElement ¤teffect) -{ - for (int i = 0;; ++i) { - QString name = QStringLiteral("filter") + QString::number(i); - if (effect->get(name.toUtf8().constData()) == nullptr) { - break; - } - // identify effect - QString tag = effect->get(name.append(QStringLiteral(".tag")).toUtf8().constData()); - QString id = effect->get(name.append(QLatin1String(".kdenlive_id")).toUtf8().constData()); - QDomElement subclipeffect = getEffectByTag(tag, id); - if (subclipeffect.isNull()) { - qCWarning(KDENLIVE_LOG) << "Region sub-effect not found"; - continue; - } - // load effect - subclipeffect = subclipeffect.cloneNode().toElement(); - subclipeffect.setAttribute(QStringLiteral("region_ix"), i); - // get effect parameters (prefixed by subfilter name) - QDomNodeList params = subclipeffect.elementsByTagName(QStringLiteral("parameter")); - for (int j = 0; j < params.count(); ++j) { - QDomElement param = params.item(j).toElement(); - setParam(param, effect->get((name + QLatin1Char('.') + param.attribute(QStringLiteral("name"))).toUtf8().constData())); - } - currenteffect.appendChild(currenteffect.ownerDocument().importNode(subclipeffect, true)); - } -} - -// static -void Timeline::setParam(QDomElement param, const QString &value) -{ - QLocale locale; - locale.setNumberOptions(QLocale::OmitGroupSeparator); - // get Kdenlive scaling parameters - double offset = locale.toDouble(param.attribute(QStringLiteral("offset"), QStringLiteral("0"))); - double fact; - QString factor = param.attribute(QStringLiteral("factor"), QStringLiteral("1")); - if (factor.contains(QLatin1Char('%'))) { - fact = EffectsController::getStringEval(factor); - } else { - fact = locale.toDouble(factor); - } - // adjust parameter if necessary - QString type = param.attribute(QStringLiteral("type")); - if (type == QLatin1String("simplekeyframe")) { - QStringList kfrs = value.split(QLatin1Char(';')); - for (int l = 0; l < kfrs.count(); ++l) { - QString fr = kfrs.at(l).section(QLatin1Char('='), 0, 0); - double val = locale.toDouble(kfrs.at(l).section(QLatin1Char('='), 1, 1)); - if (fact != 1) { - // Add 0.5 since we are converting to integer below so that 0.8 is converted to 1 and not 0 - val = val * fact + 0.5; - } - kfrs[l] = fr + QLatin1Char('=') + QString::number((int)(val + offset)); - } - param.setAttribute(QStringLiteral("keyframes"), kfrs.join(QLatin1Char(';'))); - } else if (type == QLatin1String("double") || type == QLatin1String("constant")) { - param.setAttribute(QStringLiteral("value"), locale.toDouble(value) * fact + offset); - } else { - param.setAttribute(QStringLiteral("value"), value); - } -} - -QDomElement Timeline::getEffectByTag(const QString &effecttag, const QString &effectid) -{ - QDomElement clipeffect = MainWindow::customEffects.getEffectByTag(QString(), effectid); - if (clipeffect.isNull()) { - clipeffect = MainWindow::videoEffects.getEffectByTag(effecttag, effectid); - } - if (clipeffect.isNull()) { - clipeffect = MainWindow::audioEffects.getEffectByTag(effecttag, effectid); - } - return clipeffect; -} - -QGraphicsScene *Timeline::projectScene() -{ - return m_scene; -} - -CustomTrackView *Timeline::projectView() -{ - return m_trackview; -} - -void Timeline::setEditMode(const QString &editMode) -{ - m_editMode = editMode; -} - -const QString &Timeline::editMode() const -{ - return m_editMode; -} - -void Timeline::slotVerticalZoomDown() -{ - if (m_verticalZoom == 0) { - return; - } - m_verticalZoom--; - m_doc->setZoom(m_doc->zoom().x(), m_verticalZoom); - if (m_verticalZoom == 0) { - m_trackview->setScale(m_scene->scale().x(), 0.5); - } else { - m_trackview->setScale(m_scene->scale().x(), 1); - } - adjustTrackHeaders(); - m_trackview->verticalScrollBar()->setValue(headers_area->verticalScrollBar()->value()); -} - -void Timeline::slotVerticalZoomUp() -{ - if (m_verticalZoom == 2) { - return; - } - m_verticalZoom++; - m_doc->setZoom(m_doc->zoom().x(), m_verticalZoom); - if (m_verticalZoom == 2) { - m_trackview->setScale(m_scene->scale().x(), 2); - } else { - m_trackview->setScale(m_scene->scale().x(), 1); - } - adjustTrackHeaders(); - m_trackview->verticalScrollBar()->setValue(headers_area->verticalScrollBar()->value()); -} - -void Timeline::slotRenameTrack(int ix, const QString &name) -{ - QString currentName = track(ix)->getProperty(QStringLiteral("kdenlive:track_name")); - if (currentName == name) { - return; - } - auto *configTracks = new ConfigTracksCommand(this, ix, currentName, name); - m_doc->commandStack()->push(configTracks); -} - -void Timeline::renameTrack(int ix, const QString &name) -{ - if (ix < 1) { - return; - } - Track *tk = track(ix); - if (!tk) { - return; - } - tk->setProperty(QStringLiteral("kdenlive:track_name"), name); - tk->trackHeader->renameTrack(name); - slotReloadTracks(); -} - -void Timeline::slotUpdateVerticalScroll(int /*min*/, int max) -{ - int height = 0; - if (max > 0) { - height = m_trackview->horizontalScrollBar()->height() - 1; - } - headers_container->layout()->setContentsMargins(0, m_trackview->frameWidth(), 0, height); -} - -void Timeline::updateRuler() -{ - m_ruler->update(); -} - -void Timeline::slotShowTrackEffects(int ix) -{ - m_trackview->clearSelection(); - emit showTrackEffects(ix, getTrackInfo(ix)); -} - -void Timeline::slotUpdateTrackEffectState(int ix) -{ - if (ix < 1) { - return; - } - Track *tk = track(ix); - if (!tk) { - return; - } - tk->trackHeader->updateEffectLabel(tk->effectsList.effectNames()); -} - -void Timeline::slotSaveTimelinePreview(const QString &path) -{ - QImage img(width(), height(), QImage::Format_ARGB32_Premultiplied); - img.fill(palette().base().color().rgb()); - QPainter painter(&img); - render(&painter); - painter.end(); - img = img.scaledToWidth(600, Qt::SmoothTransformation); - img.save(path); -} - -void Timeline::updateProfile(double fpsChanged) -{ - m_ruler->updateFrameSize(); - m_ruler->updateProjectFps(m_doc->timecode()); - m_ruler->setPixelPerMark(m_doc->zoom().x(), true); - slotChangeZoom(m_doc->zoom().x(), m_doc->zoom().y()); - slotSetZone(m_doc->zone(), false); - m_trackview->updateSceneFrameWidth(fpsChanged); -} - -void Timeline::checkTrackHeight(bool force) -{ - if (m_trackview->checkTrackHeight(force)) { - //m_doc->clipManager()->clearCache(); - m_ruler->updateFrameSize(); - slotChangeZoom(m_doc->zoom().x(), m_doc->zoom().y()); - slotSetZone(m_doc->zone(), false); - m_ruler->setPixelPerMark(m_doc->zoom().x(), true); - m_trackview->updateSceneFrameWidth(); - } -} - -bool Timeline::moveClip(int startTrack, qreal startPos, int endTrack, qreal endPos, PlaylistState::ClipState state, TimelineMode::EditMode mode, bool duplicate) -{ - if (startTrack == endTrack) { - return track(startTrack)->move(startPos, endPos, mode); - } - Track *sourceTrack = track(startTrack); - int pos = sourceTrack->frame(startPos); - int clipIndex = sourceTrack->playlist().get_clip_index_at(pos); - sourceTrack->playlist().lock(); - Mlt::Producer *clipProducer = sourceTrack->playlist().replace_with_blank(clipIndex); - sourceTrack->playlist().consolidate_blanks(); - if ((clipProducer == nullptr) || clipProducer->is_blank()) { - qCDebug(KDENLIVE_LOG) << "// Cannot get clip at index: " << clipIndex << " / " << startPos; - sourceTrack->playlist().unlock(); - return false; - } - sourceTrack->playlist().unlock(); - Track *destTrack = track(endTrack); - bool success = destTrack->add(endPos, clipProducer, GenTime(clipProducer->get_in(), destTrack->fps()).seconds(), - GenTime(clipProducer->get_out() + 1, destTrack->fps()).seconds(), state, duplicate, mode); - delete clipProducer; - return success; -} - -void Timeline::addTrackEffect(int trackIndex, QDomElement effect, bool addToPlaylist) -{ - if (trackIndex < 0 || trackIndex >= m_tracks.count()) { - qCWarning(KDENLIVE_LOG) << "Set Track effect outisde of range"; - return; - } - Track *sourceTrack = track(trackIndex); - effect.setAttribute(QStringLiteral("kdenlive_ix"), sourceTrack->effectsList.count() + 1); - - // Init parameter value & keyframes if required - QDomNodeList params = effect.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < params.count(); ++i) { - QDomElement e = params.item(i).toElement(); - const QString type = e.attribute(QStringLiteral("type")); - // Check if this effect has a variable parameter - if (e.attribute(QStringLiteral("default")).contains(QLatin1Char('%'))) { - if (type == QLatin1String("animatedrect")) { - QString evaluatedValue = EffectsController::getStringRectEval(e.attribute(QStringLiteral("default"))); - e.setAttribute(QStringLiteral("default"), evaluatedValue); - if (!e.hasAttribute(QStringLiteral("value"))) { - e.setAttribute(QStringLiteral("value"), evaluatedValue); - } - } else { - double evaluatedValue = EffectsController::getStringEval(e.attribute(QStringLiteral("default"))); - e.setAttribute(QStringLiteral("default"), evaluatedValue); - if (!e.hasAttribute(QStringLiteral("value")) || e.attribute(QStringLiteral("value")).startsWith(QLatin1Char('%'))) { - e.setAttribute(QStringLiteral("value"), evaluatedValue); - } - } - } - - if (!e.isNull() && (type == QLatin1String("keyframe") || type == QLatin1String("simplekeyframe"))) { - QString def = e.attribute(QStringLiteral("default")); - // Effect has a keyframe type parameter, we need to set the values - if (e.attribute(QStringLiteral("keyframes")).isEmpty()) { - e.setAttribute(QStringLiteral("keyframes"), "0:" + def + QLatin1Char(';')); - // qCDebug(KDENLIVE_LOG) << "///// EFFECT KEYFRAMES INITED: " << e.attribute("keyframes"); - // break; - } - } - - if (effect.attribute(QStringLiteral("id")) == QLatin1String("crop")) { - // default use_profile to 1 for clips with proxies to avoid problems when rendering - if (e.attribute(QStringLiteral("name")) == QLatin1String("use_profile") && m_doc->useProxy()) { - e.setAttribute(QStringLiteral("value"), QStringLiteral("1")); - } - } - } - sourceTrack->effectsList.append(effect); - if (addToPlaylist) { - sourceTrack->addTrackEffect(EffectsController::getEffectArgs(effect)); - if (effect.attribute(QStringLiteral("type")) != QLatin1String("audio")) { - invalidateTrack(trackIndex); - } - } -} - -bool Timeline::removeTrackEffect(int trackIndex, int effectIndex, const QDomElement &effect) -{ - if (trackIndex < 0 || trackIndex >= m_tracks.count()) { - qCWarning(KDENLIVE_LOG) << "Set Track effect outisde of range"; - return false; - } - int toRemove = effect.attribute(QStringLiteral("kdenlive_ix")).toInt(); - Track *sourceTrack = track(trackIndex); - bool success = sourceTrack->removeTrackEffect(effectIndex, true); - if (success) { - int max = sourceTrack->effectsList.count(); - for (int i = 0; i < max; ++i) { - int index = sourceTrack->effectsList.at(i).attribute(QStringLiteral("kdenlive_ix")).toInt(); - if (toRemove == index) { - sourceTrack->effectsList.removeAt(toRemove); - break; - } - } - if (effect.attribute(QStringLiteral("type")) != QLatin1String("audio")) { - invalidateTrack(trackIndex); - } - } - return success; -} - -void Timeline::setTrackEffect(int trackIndex, int effectIndex, QDomElement effect) -{ - if (trackIndex < 0 || trackIndex >= m_tracks.count()) { - qCWarning(KDENLIVE_LOG) << "Set Track effect outisde of range"; - return; - } - Track *sourceTrack = track(trackIndex); - int max = sourceTrack->effectsList.count(); - if (effectIndex <= 0 || effectIndex > (max) || effect.isNull()) { - // qCDebug(KDENLIVE_LOG) << "Invalid effect index: " << effectIndex; - return; - } - sourceTrack->effectsList.removeAt(effect.attribute(QStringLiteral("kdenlive_ix")).toInt()); - effect.setAttribute(QStringLiteral("kdenlive_ix"), effectIndex); - sourceTrack->effectsList.insert(effect); - if (effect.attribute(QStringLiteral("type")) != QLatin1String("audio")) { - invalidateTrack(trackIndex); - } -} - -bool Timeline::enableTrackEffects(int trackIndex, const QList &effectIndexes, bool disable) -{ - if (trackIndex < 0 || trackIndex >= m_tracks.count()) { - qCWarning(KDENLIVE_LOG) << "Set Track effect outisde of range"; - return false; - } - Track *sourceTrack = track(trackIndex); - EffectsList list = sourceTrack->effectsList; - QDomElement effect; - bool hasVideoEffect = false; - for (int i = 0; i < effectIndexes.count(); ++i) { - effect = list.itemFromIndex(effectIndexes.at(i)); - if (!effect.isNull()) { - effect.setAttribute(QStringLiteral("disable"), (int)disable); - if (effect.attribute(QStringLiteral("type")) != QLatin1String("audio")) { - hasVideoEffect = true; - } - } - } - if (hasVideoEffect) { - invalidateTrack(trackIndex); - } - return hasVideoEffect; -} - -const EffectsList Timeline::getTrackEffects(int trackIndex) -{ - if (trackIndex < 0 || trackIndex >= m_tracks.count()) { - qCWarning(KDENLIVE_LOG) << "Set Track effect outisde of range"; - return EffectsList(); - } - Track *sourceTrack = track(trackIndex); - return sourceTrack->effectsList; -} - -QDomElement Timeline::getTrackEffect(int trackIndex, int effectIndex) -{ - if (trackIndex < 0 || trackIndex >= m_tracks.count()) { - qCWarning(KDENLIVE_LOG) << "Set Track effect outisde of range"; - return QDomElement(); - } - Track *sourceTrack = track(trackIndex); - EffectsList list = sourceTrack->effectsList; - if (effectIndex > list.count() || effectIndex < 1 || list.itemFromIndex(effectIndex).isNull()) { - return QDomElement(); - } - return list.itemFromIndex(effectIndex).cloneNode().toElement(); -} - -int Timeline::hasTrackEffect(int trackIndex, const QString &tag, const QString &id) -{ - if (trackIndex < 0 || trackIndex >= m_tracks.count()) { - qCWarning(KDENLIVE_LOG) << "Set Track effect outisde of range"; - return -1; - } - Track *sourceTrack = track(trackIndex); - EffectsList list = sourceTrack->effectsList; - return list.hasEffect(tag, id); -} - - -double Timeline::fps() const -{ - return pCore->getCurrentFps(); -} - -QPoint Timeline::getTracksCount() -{ - int audioTracks = 0; - int videoTracks = 0; - int max = m_tracks.count(); - // Ignore black background track, start at one - for (int i = 1; i < max; i++) { - Track *tk = track(i); - if (tk->type == AudioTrack) { - audioTracks++; - } else { - videoTracks++; - } - } - return QPoint(videoTracks, audioTracks); -} - -int Timeline::getTrackSpaceLength(int trackIndex, int pos, bool fromBlankStart) -{ - if (trackIndex < 0 || trackIndex >= m_tracks.count()) { - qCWarning(KDENLIVE_LOG) << "Set Track effect outisde of range"; - return 0; - } - return track(trackIndex)->getBlankLength(pos, fromBlankStart); -} - -void Timeline::updateClipProperties(const QString &id, const QMap &properties) -{ - for (int i = 1; i < m_tracks.count(); i++) { - track(i)->updateClipProperties(id, properties); - } -} - -int Timeline::changeClipSpeed(const ItemInfo &info, const ItemInfo &speedIndependantInfo, PlaylistState::ClipState state, double speed, int strobe, - Mlt::Producer *originalProd, bool removeEffect) -{ - QLocale locale; - QString url = QString::fromUtf8(originalProd->get("resource")); - Track::SlowmoInfo slowInfo; - slowInfo.speed = speed; - slowInfo.strobe = strobe; - slowInfo.state = state; - url.prepend(slowInfo.toString(locale)); - // if (strobe > 1) url.append("&strobe=" + QString::number(strobe)); - Mlt::Producer *prod; - if (removeEffect) { - // We want to remove framebuffer producer, so pass original - prod = originalProd; - } else { - // Pass slowmotion producer - prod = m_doc->renderer()->getSlowmotionProducer(url); - } - QString id = originalProd->get("id"); - id = id.section(QLatin1Char('_'), 0, 0); - Mlt::Properties passProperties; - Mlt::Properties original(originalProd->get_properties()); - passProperties.pass_list(original, ClipController::getPassPropertiesList(false)); - return track(info.track)->changeClipSpeed(info, speedIndependantInfo, state, speed, strobe, prod, id, passProperties); -} - -void Timeline::duplicateClipOnPlaylist(int tk, qreal startPos, int offset, Mlt::Producer *prod) -{ - Track *sourceTrack = track(tk); - int pos = sourceTrack->frame(startPos); - int clipIndex = sourceTrack->playlist().get_clip_index_at(pos); - if (sourceTrack->playlist().is_blank(clipIndex)) { - qCDebug(KDENLIVE_LOG) << "// ERROR FINDING CLIP on TK: " << tk << ", FRM: " << pos; - } - Mlt::Producer *clipProducer = sourceTrack->playlist().get_clip(clipIndex); - Clip clp(clipProducer->parent()); - Mlt::Producer *cln = clp.clone(); - - // Clip effects must be moved from clip to the playlist entry, so first delete them from parent clip - Clip(*cln).deleteEffects(); - cln->set_in_and_out(clipProducer->get_in(), clipProducer->get_out()); - Mlt::Playlist trackPlaylist((mlt_playlist)prod->get_service()); - trackPlaylist.lock(); - - int newIdx = trackPlaylist.insert_at(pos - offset, cln, 1); - // Re-add source effects in playlist - Mlt::Producer *inPlaylist = trackPlaylist.get_clip(newIdx); - if (inPlaylist) { - Clip(*inPlaylist).addEffects(*clipProducer); - delete inPlaylist; - } - - trackPlaylist.unlock(); - delete clipProducer; - delete cln; - delete prod; -} - -int Timeline::getSpaceLength(const GenTime &pos, int tk, bool fromBlankStart) -{ - Track *sourceTrack = track(tk); - if (!sourceTrack) { - return 0; - } - int insertPos = pos.frames(pCore->getCurrentFps()); - return sourceTrack->spaceLength(insertPos, fromBlankStart); -} - -void Timeline::disableTimelineEffects(bool disable) -{ - for (int i = 1; i < tracksCount(); i++) { - track(i)->disableEffects(disable); - } -} - -void Timeline::importPlaylist(const ItemInfo &info, const QMap &idMaps, const QDomDocument &doc, QUndoCommand *command) -{ - projectView()->importPlaylist(info, idMaps, doc, command); -} - -void Timeline::refreshTrackActions() -{ - int tracks = tracksCount(); - if (tracks > 3) { - return; - } - for (QAction *action : m_trackActions) { - if (action->data().toString() == QLatin1String("delete_track")) { - action->setEnabled(tracks > 2); - } - } -} - -void Timeline::slotMultitrackView(bool enable) -{ - multitrackView = enable; - transitionHandler->enableMultiTrack(enable); -} - -void Timeline::connectOverlayTrack(bool enable) -{ - if (!m_hasOverlayTrack && !m_usePreview) { - return; - } - m_tractor->lock(); - if (enable) { - // Re-add overlaytrack - if (m_usePreview) { - m_timelinePreview->reconnectTrack(); - } - if (m_hasOverlayTrack) { - m_tractor->insert_track(*m_overlayTrack, tracksCount() + 1); - delete m_overlayTrack; - m_overlayTrack = nullptr; - } - } else { - if (m_usePreview) { - m_timelinePreview->disconnectTrack(); - } - if (m_hasOverlayTrack) { - m_overlayTrack = m_tractor->track(tracksCount()); - m_tractor->remove_track(tracksCount()); - } - } - m_tractor->unlock(); -} - -void Timeline::removeSplitOverlay() -{ - if (!m_hasOverlayTrack) { - return; - } - m_tractor->lock(); - Mlt::Producer *prod = m_tractor->track(tracksCount()); - if (strcmp(prod->get("id"), "overlay_track") == 0) { - m_tractor->remove_track(tracksCount()); - } else { - qCWarning(KDENLIVE_LOG) << "Overlay track not found, something is wrong!!"; - } - delete prod; - m_hasOverlayTrack = false; - m_tractor->unlock(); -} - -bool Timeline::createOverlay(Mlt::Filter *filter, int tk, int startPos) -{ - Track *sourceTrack = track(tk); - if (!sourceTrack) { - return false; - } - m_tractor->lock(); - int clipIndex = sourceTrack->playlist().get_clip_index_at(startPos); - Mlt::Producer *clipProducer = sourceTrack->playlist().get_clip(clipIndex); - Clip clp(clipProducer->parent()); - Mlt::Producer *cln = clp.clone(); - Clip(*cln).deleteEffects(); - cln->set_in_and_out(clipProducer->get_in(), clipProducer->get_out()); - Mlt::Playlist overlay(*m_tractor->profile()); - Mlt::Tractor trac(*m_tractor->profile()); - trac.set_track(*clipProducer, 0); - trac.set_track(*cln, 1); - cln->attach(*filter); - QString splitTransition = transitionHandler->compositeTransition(); - Mlt::Transition t(*m_tractor->profile(), splitTransition.toUtf8().constData()); - t.set("always_active", 1); - trac.plant_transition(t, 0, 1); - delete cln; - delete clipProducer; - overlay.insert_blank(0, startPos); - Mlt::Producer split(trac.get_producer()); - overlay.insert_at(startPos, &split, 1); - int trackIndex = tracksCount(); - m_tractor->insert_track(overlay, trackIndex); - Mlt::Producer *overlayTrack = m_tractor->track(trackIndex); - overlayTrack->set("hide", 2); - overlayTrack->set("id", "overlay_track"); - delete overlayTrack; - m_hasOverlayTrack = true; - m_tractor->unlock(); - return true; -} - -bool Timeline::createRippleWindow(int tk, int startPos, OperationType /*mode*/) -{ - if (m_hasOverlayTrack) { - return true; - } - Track *sourceTrack = track(tk); - if (!sourceTrack) { - return false; - } - m_tractor->lock(); - Mlt::Playlist playlist = sourceTrack->playlist(); - int clipIndex = playlist.get_clip_index_at(startPos); - if (playlist.is_blank(clipIndex - 1)) { - // No clip to roll - m_tractor->unlock(); - return false; - } - Mlt::Producer *firstClip = playlist.get_clip(clipIndex - 1); - Mlt::Producer *secondClip = playlist.get_clip(clipIndex); - if ((firstClip == nullptr) || !firstClip->is_valid()) { - m_tractor->unlock(); - emit displayMessage(i18n("Cannot find first clip to perform ripple trim"), ErrorMessage); - return false; - } - if ((secondClip == nullptr) || !secondClip->is_valid()) { - m_tractor->unlock(); - emit displayMessage(i18n("Cannot find second clip to perform ripple trim"), ErrorMessage); - return false; - } - // Create duplicate of second clip - Clip clp2(secondClip->parent()); - Mlt::Producer *cln2 = clp2.clone(); - Clip(*cln2).addEffects(*secondClip); - // Create copy of first clip - auto *cln = new Mlt::Producer(firstClip->parent()); - cln->set_in_and_out(firstClip->get_in(), -1); - Clip(*cln).addEffects(*firstClip); - int secondStart = playlist.clip_start(clipIndex); - bool rolling = m_trackview->operationMode() == RollingStart || m_trackview->operationMode() == RollingEnd; - if (rolling) { - secondStart -= secondClip->get_in(); - } else { - // cln2->set_in_and_out(secondClip->get_in(), secondClip->get_out()); - qCDebug(KDENLIVE_LOG) << "* * *INIT RIPPLE; CLP START: " << secondClip->get_in(); - } - int rippleStart = playlist.clip_start(clipIndex - 1); - - Mlt::Filter f1(*m_tractor->profile(), "affine"); - f1.set("transition.geometry", "50% 0 50% 50%"); - f1.set("transition.always_active", 1); - cln2->attach(f1); - - auto *ripple1 = new Mlt::Playlist(*m_tractor->profile()); - if (secondStart < 0) { - cln2->set_in_and_out(-secondStart, -1); - secondStart = 0; - } - if (secondStart > 0) { - ripple1->insert_blank(0, secondStart); - } - ripple1->insert_at(secondStart, cln2, 1); - int ix = ripple1->get_clip_index_at(secondStart); - ripple1->resize_clip(ix, secondClip->get_in(), secondClip->get_out()); - qCDebug(KDENLIVE_LOG) << "* * *INIT RIPPLE; REAL START: " << cln2->get_in() << " / " << secondStart; - Mlt::Playlist ripple2(*m_tractor->profile()); - ripple2.insert_blank(0, rippleStart); - ripple2.insert_at(rippleStart, cln, 1); - - Mlt::Playlist overlay(*m_tractor->profile()); - Mlt::Tractor trac(*m_tractor->profile()); - // TODO: use GPU effect/trans with movit - Mlt::Transition t(*m_tractor->profile(), "affine"); - t.set("geometry", "0% 0 50% 50%"); - t.set("always_active", 1); - - trac.set_track(*ripple1, 0); - trac.set_track(ripple2, 1); - trac.plant_transition(t, 0, 1); - delete cln; - delete cln2; - delete firstClip; - delete secondClip; - Mlt::Producer split(trac.get_producer()); - overlay.insert_at(0, &split, 1); - int trackIndex = tracksCount(); - m_tractor->insert_track(overlay, trackIndex); - Mlt::Producer *overlayTrack = m_tractor->track(trackIndex); - overlayTrack->set("hide", 2); - overlayTrack->set("id", "overlay_track"); - delete overlayTrack; - m_hasOverlayTrack = true; - m_tractor->unlock(); - AbstractToolManager *mgr = m_trackview->toolManager(AbstractToolManager::TrimType); - TrimManager *trimmer = qobject_cast(mgr); - trimmer->initRipple(ripple1, secondStart, m_doc->renderer()); - return true; -} - -void Timeline::switchTrackTarget() -{ - if (!KdenliveSettings::splitaudio()) { - // This feature is only available on split mode - return; - } - Track *current = m_tracks.at(m_trackview->selectedTrack()); - TrackType trackType = current->info().type; - if (trackType == VideoTrack) { - if (m_trackview->selectedTrack() == videoTarget) { - // Switch off - current->trackHeader->switchTarget(false); - videoTarget = -1; - } else { - if (videoTarget > -1) { - m_tracks.at(videoTarget)->trackHeader->switchTarget(false); - } - current->trackHeader->switchTarget(true); - videoTarget = m_trackview->selectedTrack(); - } - } else if (trackType == AudioTrack) { - if (m_trackview->selectedTrack() == audioTarget) { - // Switch off - current->trackHeader->switchTarget(false); - audioTarget = -1; - } else { - if (audioTarget > -1) { - m_tracks.at(audioTarget)->trackHeader->switchTarget(false); - } - current->trackHeader->switchTarget(true); - audioTarget = m_trackview->selectedTrack(); - } - } -} - -void Timeline::slotEnableZone(bool enable) -{ - KdenliveSettings::setUseTimelineZoneToEdit(enable); - m_ruler->activateZone(); -} - -void Timeline::stopPreviewRender() -{ - if (m_timelinePreview) { - m_timelinePreview->abortRendering(); - } -} - -void Timeline::invalidateRange(const ItemInfo &info) -{ - if (!m_timelinePreview) { - return; - } - if (info.isValid()) { - m_timelinePreview->invalidatePreview(info.startPos.frames(pCore->getCurrentFps()), info.endPos.frames(pCore->getCurrentFps())); - } else { - m_timelinePreview->invalidatePreview(0, m_trackview->duration()); - } -} - -void Timeline::loadPreviewRender() -{ - QString chunks = m_doc->getDocumentProperty(QStringLiteral("previewchunks")); - QString dirty = m_doc->getDocumentProperty(QStringLiteral("dirtypreviewchunks")); - m_disablePreview->blockSignals(true); - m_disablePreview->setChecked(m_doc->getDocumentProperty(QStringLiteral("disablepreview")).toInt() != 0); - m_disablePreview->blockSignals(false); - QDateTime documentDate = QFileInfo(m_doc->url().toLocalFile()).lastModified(); - if (!chunks.isEmpty() || !dirty.isEmpty()) { - if (!m_timelinePreview) { - initializePreview(); - } - if ((m_timelinePreview == nullptr) || m_disablePreview->isChecked()) { - return; - } - m_timelinePreview->buildPreviewTrack(); - QList renderedChunks; - QList dirtyChunks; - QStringList chunksList = chunks.split(QLatin1Char(','), QString::SkipEmptyParts); - QStringList dirtyList = dirty.split(QLatin1Char(','), QString::SkipEmptyParts); - for (const QString &frame : chunksList) { - renderedChunks << frame.toInt(); - } - for (const QString &frame : dirtyList) { - dirtyChunks << frame.toInt(); - } - //m_timelinePreview->loadChunks(renderedChunks, dirtyChunks, documentDate); - m_usePreview = true; - } else { - m_ruler->hidePreview(true); - } -} - -void Timeline::updatePreviewSettings(const QString &profile) -{ - if (profile.isEmpty()) { - return; - } - QString params = profile.section(QLatin1Char(';'), 0, 0); - QString ext = profile.section(QLatin1Char(';'), 1, 1); - if (params != m_doc->getDocumentProperty(QStringLiteral("previewparameters")) || ext != m_doc->getDocumentProperty(QStringLiteral("previewextension"))) { - // Timeline preview params changed, delete all existing previews. - invalidateRange(ItemInfo()); - m_doc->setDocumentProperty(QStringLiteral("previewparameters"), params); - m_doc->setDocumentProperty(QStringLiteral("previewextension"), ext); - initializePreview(); - } -} - -void Timeline::invalidateTrack(int ix) -{ - if (!m_timelinePreview) { - return; - } - Track *tk = track(ix); - const QList visibleRange = tk->visibleClips(); - for (const QPoint &p : visibleRange) { - m_timelinePreview->invalidatePreview(p.x(), p.y()); - } -} - -void Timeline::initializePreview() -{ - if (m_timelinePreview) { - // Update parameters - if (!m_timelinePreview->loadParams()) { - if (m_usePreview) { - // Disconnect preview track - m_timelinePreview->disconnectTrack(); - m_ruler->hidePreview(true); - m_usePreview = false; - } - delete m_timelinePreview; - m_timelinePreview = nullptr; - } - } else { - m_timelinePreview = nullptr; //new PreviewManager(m_tractor); - if (!m_timelinePreview->initialize()) { - // TODO warn user - m_ruler->hidePreview(true); - delete m_timelinePreview; - m_timelinePreview = nullptr; - } else { - m_ruler->hidePreview(false); - } - } - QAction *previewRender = m_doc->getAction(QStringLiteral("prerender_timeline_zone")); - if (previewRender) { - previewRender->setEnabled(m_timelinePreview != nullptr); - } - m_disablePreview->setEnabled(m_timelinePreview != nullptr); - m_disablePreview->blockSignals(true); - m_disablePreview->setChecked(false); - m_disablePreview->blockSignals(false); -} - -void Timeline::startPreviewRender() -{ - // Timeline preview stuff - if (!m_timelinePreview) { - initializePreview(); - } else if (m_disablePreview->isChecked()) { - m_disablePreview->setChecked(false); - disablePreview(false); - } - if (m_timelinePreview) { - if (!m_usePreview) { - m_timelinePreview->buildPreviewTrack(); - m_usePreview = true; - } - m_timelinePreview->startPreviewRender(); - } -} - -void Timeline::disablePreview(bool disable) -{ - if (disable) { - m_timelinePreview->deletePreviewTrack(); - m_ruler->hidePreview(true); - m_usePreview = false; - } else { - if (!m_usePreview) { - if (!m_timelinePreview->buildPreviewTrack()) { - // preview track already exists, reconnect - m_tractor->lock(); - m_timelinePreview->reconnectTrack(); - m_tractor->unlock(); - } - QPair chunks = m_ruler->previewChunks(); - //m_timelinePreview->loadChunks(chunks.first, chunks.second, QDateTime()); - m_ruler->hidePreview(false); - m_usePreview = true; - } - } -} - -void Timeline::addPreviewRange(bool add) -{ - if (m_timelinePreview) { - m_timelinePreview->addPreviewRange(QPoint(), add); - } -} - -void Timeline::clearPreviewRange() -{ - if (m_timelinePreview) { - m_timelinePreview->clearPreviewRange(); - } -} - -void Timeline::storeHeaderSize(int, int) -{ - //KdenliveSettings::setTimelineheaderwidth(splitter->saveState().toBase64()); -} - -void Timeline::switchComposite(int mode) -{ - if (m_tracks.isEmpty()) { - return; - } - int maxTrack = tracksCount(); - // check video tracks - QList videoTracks; - for (int i = 1; i < maxTrack; i++) { - if ((m_tracks.at(i)->trackHeader != nullptr) && m_tracks.at(i)->info().type == VideoTrack) { - videoTracks << i; - } - } - transitionHandler->rebuildTransitions(mode, videoTracks, maxTrack); - m_doc->renderer()->doRefresh(); - m_doc->setModified(); -} - -bool Timeline::hideClip(const QString &id, bool hide) -{ - bool trackHidden = false; - for (int i = 1; i < m_tracks.count(); i++) { - trackHidden |= static_cast(track(i)->hideClip(m_trackview->seekPosition(), id, hide)); - } - return trackHidden; -} diff --git a/src/timeline/timeline.h b/src/timeline/timeline.h deleted file mode 100644 index df01042f1..000000000 --- a/src/timeline/timeline.h +++ /dev/null @@ -1,301 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -/** -* @class Timeline -* @brief Manages the timline -* @author Jean-Baptiste Mardelle -*/ - -#ifndef TRACKVIEW_H -#define TRACKVIEW_H - -#include "definitions.h" -#include "effectslist/effectslist.h" -#include "timeline/customtrackscene.h" -#include "ui_timeline_ui.h" - -#include -#include -#include - -#include - -class Track; -class ClipItem; -class CustomTrackView; -class KdenliveDoc; -class TransitionHandler; -class CustomRuler; -class QUndoCommand; -class PreviewManager; - -class ScrollEventEater : public QObject -{ - Q_OBJECT -public: - explicit ScrollEventEater(QObject *parent = nullptr); - -protected: - bool eventFilter(QObject *obj, QEvent *event) override; -}; - -class Timeline : public QWidget, public Ui::TimeLine_UI -{ - Q_OBJECT - -public: - explicit Timeline(KdenliveDoc *doc, const QList &actions, const QList &rulerActions, bool *ok, QWidget *parent = nullptr); - virtual ~Timeline(); - - /** @brief is multitrack view (split screen for tracks) enabled */ - bool multitrackView; - int videoTarget; - int audioTarget; - Track *track(int i); - /** @brief Number of tracks in the MLT playlist. */ - int tracksCount() const; - /** @brief Number of visible tracks (= tracksCount() - 1 ) because black trck is not visible to user. */ - int visibleTracksCount() const; - void setEditMode(const QString &editMode); - const QString &editMode() const; - QGraphicsScene *projectScene(); - CustomTrackView *projectView(); - int duration() const; - KdenliveDoc *document(); - void refresh(); - int outPoint() const; - int inPoint() const; - int fitZoom() const; - /** @brief This object handles all transition operation. */ - TransitionHandler *transitionHandler; - void lockTrack(int ix, bool lock); - bool isTrackLocked(int ix); - /** @brief Dis / enable video for a track. */ - void doSwitchTrackVideo(int ix, bool hide); - /** @brief Dis / enable audio for a track. */ - void doSwitchTrackAudio(int ix, bool mute); - - /** @brief Updates (redraws) the ruler. - * - * Used to change from displaying frames to timecode or vice versa. */ - void updateRuler(); - - /** @brief Parse tracks to see if project has audio in it. - * - * Parses all tracks to check if there is audio data. */ - bool checkProjectAudio(); - - /** @brief Load guides from data */ - void loadGuides(const QMap &guidesData); - - void checkTrackHeight(bool force = false); - void updatePalette(); - void refreshIcons(); - /** @brief Returns a kdenlive effect xml description from an effect tag / id */ - static QDomElement getEffectByTag(const QString &effecttag, const QString &effectid); - /** @brief Move a clip between tracks */ - bool moveClip(int startTrack, qreal startPos, int endTrack, qreal endPos, PlaylistState::ClipState state, TimelineMode::EditMode mode, bool duplicate); - void renameTrack(int ix, const QString &name); - void updateTrackState(int ix, int state); - /** @brief Returns info about a track. - * @param ix The track number in MLT's coordinates (0 = black track, 1 = bottom audio, etc) - * deprecated use string version with track name instead */ - TrackInfo getTrackInfo(int ix); - void setTrackInfo(int trackIndex, const TrackInfo &info); - QList getTracksInfo(); - QStringList getTrackNames(); - void addTrackEffect(int trackIndex, QDomElement effect, bool addToPlaylist = true); - bool removeTrackEffect(int trackIndex, int effectIndex, const QDomElement &effect); - void setTrackEffect(int trackIndex, int effectIndex, QDomElement effect); - bool enableTrackEffects(int trackIndex, const QList &effectIndexes, bool disable); - const EffectsList getTrackEffects(int trackIndex); - QDomElement getTrackEffect(int trackIndex, int effectIndex); - int hasTrackEffect(int trackIndex, const QString &tag, const QString &id); - double fps() const; - QPoint getTracksCount(); - /** @brief Check if we have a blank space on selected track. - * Returns -1 if track is shorter, 0 if not blank and > 0 for blank length */ - int getTrackSpaceLength(int trackIndex, int pos, bool fromBlankStart); - void updateClipProperties(const QString &id, const QMap &properties); - int changeClipSpeed(const ItemInfo &info, const ItemInfo &speedIndependantInfo, PlaylistState::ClipState state, double speed, int strobe, - Mlt::Producer *originalProd, bool removeEffect = false); - /** @brief Set an effect's XML accordingly to MLT::filter values. */ - static void setParam(QDomElement param, const QString &value); - int getTracks(); - void getTransitions(); - void refreshTractor(); - void duplicateClipOnPlaylist(int tk, qreal startPos, int offset, Mlt::Producer *prod); - int getSpaceLength(const GenTime &pos, int tk, bool fromBlankStart); - void blockTrackSignals(bool block); - /** @brief Load document */ - void loadTimeline(); - /** @brief Dis/enable all effects in timeline*/ - void disableTimelineEffects(bool disable); - QString getKeyframes(Mlt::Service service, int &ix, const QDomElement &e); - void getSubfilters(Mlt::Filter *effect, QDomElement ¤teffect); - static bool isSlide(QString geometry); - /** @brief Import amultitrack MLT playlist in timeline */ - void importPlaylist(const ItemInfo &info, const QMap &idMaps, const QDomDocument &doc, QUndoCommand *command); - /** @brief Creates an overlay track with a filtered clip */ - bool createOverlay(Mlt::Filter *filter, int tk, int startPos); - /** @brief Creates an overlay track with a ripple transition*/ - bool createRippleWindow(int tk, int startPos, OperationType mode); - void removeSplitOverlay(); - /** @brief Temporarily add/remove track before saving */ - void connectOverlayTrack(bool enable); - /** @brief Update composite and mix transitions's tracks */ - void refreshTransitions(); - /** @brief Switch current track target state */ - void switchTrackTarget(); - /** @brief Refresh Header Leds */ - void updateHeaders(); - /** @brief Returns true if position is on the last clip */ - bool isLastClip(const ItemInfo &info); - /** @brief find lowest video track in timeline. */ - int getLowestVideoTrack(); - /** @brief Returns the document properties with some added values from timeline. */ - QMap documentProperties(); - void reloadTrack(int ix, int start = 0, int end = -1); - void reloadTrack(const ItemInfo &info, bool includeLastFrame); - /** @brief Add or remove current timeline zone to preview render zone. */ - void addPreviewRange(bool add); - /** @brief Resets all preview render zones. */ - void clearPreviewRange(); - /** @brief Check if timeline preview profile changed and remove preview files if necessary. */ - void updatePreviewSettings(const QString &profile); - /** @brief invalidate timeline preview for visible clips in a track */ - void invalidateTrack(int ix); - /** @brief Start rendering preview rendering range. */ - void startPreviewRender(); - /** @brief Toggle current project's compositing mode. */ - void switchComposite(int mode); - /** @brief Temporarily hide a clip if it is at cursor position so that we can extract an image. - * @returns true if a track was temporarily hidden - */ - bool hideClip(const QString &id, bool hide); - -public slots: - void slotDeleteClip(const QString &clipId, QUndoCommand *deleteCommand); - void slotChangeZoom(int horizontal, int vertical = -1, bool zoomOnMouse = false); - void setDuration(int dur); - void slotSetZone(const QPoint &p, bool updateDocumentProperties = true); - /** @brief Save a snapshot image of current timeline view */ - void slotSaveTimelinePreview(const QString &path); - void checkDuration(); - void slotShowTrackEffects(int); - void updateProfile(double fpsChanged); - /** @brief Enable/disable multitrack view (split monitor in 4) */ - void slotMultitrackView(bool enable); - /** @brief Stop rendering preview. */ - void stopPreviewRender(); - /** @brief Invalidate a preview rendering range. */ - void invalidateRange(const ItemInfo &info = ItemInfo()); - -private: - Mlt::Tractor *m_tractor; - QList m_tracks; - /** @brief number of special overlay tracks to preview effects */ - bool m_hasOverlayTrack; - Mlt::Producer *m_overlayTrack; - CustomRuler *m_ruler; - CustomTrackView *m_trackview; - QList m_invalidProducers; - double m_scale; - QString m_editMode; - CustomTrackScene *m_scene; - /** @brief A list of producer ids to be replaced when opening a corrupted document*/ - QMap m_replacementProducerIds; - - KdenliveDoc *m_doc; - int m_verticalZoom; - QString m_documentErrors; - QList m_trackActions; - /** @brief sometimes grouped commands quickly send invalidate commands, so wait a little bit before processing*/ - PreviewManager *m_timelinePreview; - bool m_usePreview; - QAction *m_disablePreview; - - void adjustTrackHeaders(); - - void parseDocument(const QDomDocument &doc); - int loadTrack(int ix, int offset, Mlt::Playlist &playlist, int start = 0, int end = -1, bool updateReferences = true); - void getEffects(Mlt::Service &service, ClipItem *clip, int track = 0); - void adjustDouble(QDomElement &e, const QString &value); - - /** @brief Adjust kdenlive effect xml parameters to the MLT value*/ - void adjustparameterValue(QDomNodeList clipeffectparams, const QString ¶mname, const QString ¶mvalue); - /** @brief Enable/disable track actions depending on number of tracks */ - void refreshTrackActions(); - /** @brief load existing timeline previews */ - void loadPreviewRender(); - void initializePreview(); - -private slots: - void setCursorPos(int pos); - void moveCursorPos(int pos); - /** @brief The tracks count or a track name changed, rebuild and notify */ - void slotReloadTracks(); - void slotVerticalZoomDown(); - void slotVerticalZoomUp(); - /** @brief Changes the name of a track. - * @param ix Number of the track - * @param name New name */ - void slotRenameTrack(int ix, const QString &name); - void slotRepaintTracks(); - - /** @brief Adjusts the margins of the header area. - * - * Avoid a shift between header area and trackview if - * the horizontal scrollbar is visible and the position - * of the vertical scrollbar is maximal */ - void slotUpdateVerticalScroll(int min, int max); - /** @brief Update the track label showing applied effects.*/ - void slotUpdateTrackEffectState(int); - /** @brief Toggle use of timeline zone for editing.*/ - void slotEnableZone(bool enable); - /** @brief Dis / enable video for a track. */ - void switchTrackVideo(int ix, bool hide); - /** @brief Dis / enable audio for a track. */ - void switchTrackAudio(int ix, bool mute); - /** @brief Dis / enable timeline preview. */ - void disablePreview(bool disable); - /** @brief Resize ruler layout to adjust for timeline preview. */ - void resizeRuler(int height); - /** @brief The timeline track headers were resized, store width. */ - void storeHeaderSize(int pos, int index); - -signals: - void mousePosition(int); - void cursorMoved(); - void zoneMoved(int, int); - void configTrack(); - void updateTracksInfo(); - void setZoom(int); - void showTrackEffects(int, const TrackInfo &); - /** @brief Indicate how many clips we are going to load */ - void startLoadingBin(int); - /** @brief Indicate which clip we are currently loading */ - void loadingBin(int); - /** @brief We are about to reload timeline, reset bin clip usage */ - void resetUsageCount(); - void displayMessage(const QString &, MessageType); -}; - -#endif diff --git a/src/timeline/timelinecommands.cpp b/src/timeline/timelinecommands.cpp deleted file mode 100644 index e55054287..000000000 --- a/src/timeline/timelinecommands.cpp +++ /dev/null @@ -1,899 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-2012 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * Copyright (C) 2008 by Marco Gittler (g.marco@freenet.de) * - * Copyright (C) 2010 by Till Theato (root@ttill.de) * - * Copyright (C) 2014 by Vincent Pinon (vpinon@april.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "timelinecommands.h" -#include "customtrackview.h" -#include "timeline.h" - -#include - -AddEffectCommand::AddEffectCommand(CustomTrackView *view, const int track, const GenTime &pos, const QDomElement &effect, bool doIt, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_track(track) - , m_effect(effect) - , m_pos(pos) - , m_doIt(doIt) -{ - QString effectName; - QDomElement namenode = m_effect.firstChildElement(QStringLiteral("name")); - if (!namenode.isNull()) { - effectName = i18n(namenode.text().toUtf8().constData()); - } else { - effectName = i18n("effect"); - } - if (doIt) { - setText(i18n("Add %1", effectName)); - } else { - setText(i18n("Delete %1", effectName)); - } -} -// virtual -void AddEffectCommand::undo() -{ - if (m_doIt) { - m_view->deleteEffect(m_track, m_pos, m_effect); - } else { - m_view->addEffect(m_track, m_pos, m_effect); - } -} -// virtual -void AddEffectCommand::redo() -{ - if (m_doIt) { - m_view->addEffect(m_track, m_pos, m_effect); - } else { - m_view->deleteEffect(m_track, m_pos, m_effect); - } -} - -AddTimelineClipCommand::AddTimelineClipCommand(CustomTrackView *view, const QString &clipId, const ItemInfo &info, const EffectsList &effects, - PlaylistState::ClipState state, bool doIt, bool doRemove, bool refreshMonitor, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_clipId(clipId) - , m_clipInfo(info) - , m_effects(effects) - , m_state(state) - , m_doIt(doIt) - , m_remove(doRemove) - , m_refresh(refreshMonitor) -{ - if (!m_remove) { - setText(i18n("Add timeline clip")); - } else { - setText(i18n("Delete timeline clip")); - } -} -// virtual -void AddTimelineClipCommand::undo() -{ - if (!m_remove) { - m_view->deleteClip(m_clipInfo); - } else { - m_view->addClip(m_clipId, m_clipInfo, m_effects, m_state); - } -} -// virtual -void AddTimelineClipCommand::redo() -{ - if (m_doIt) { - if (!m_remove) { - m_view->addClip(m_clipId, m_clipInfo, m_effects, m_state); - } else { - m_view->deleteClip(m_clipInfo); - } - } - m_doIt = true; -} - -AddTrackCommand::AddTrackCommand(CustomTrackView *view, int ix, const TrackInfo &info, bool addTrack, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_ix(ix) - , m_addTrack(addTrack) - , m_info(info) -{ - if (addTrack) { - setText(i18n("Add track")); - } else { - setText(i18n("Delete track")); - } -} -// virtual -void AddTrackCommand::undo() -{ - if (m_addTrack) { - m_view->removeTrack(m_ix); - } else { - m_view->addTrack(m_info, m_ix); - } -} -// virtual -void AddTrackCommand::redo() -{ - if (m_addTrack) { - m_view->addTrack(m_info, m_ix); - } else { - m_view->removeTrack(m_ix); - } -} - -AddTransitionCommand::AddTransitionCommand(CustomTrackView *view, const ItemInfo &info, int transitiontrack, const QDomElement ¶ms, bool remove, bool doIt, - QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_info(info) - , m_params(params) - , m_track(transitiontrack) - , m_doIt(doIt) - , m_remove(remove) -{ - if (m_remove) { - setText(i18n("Delete transition from clip")); - } else { - setText(i18n("Add transition to clip")); - } - if (parent) { - // command has a parent, so there are several operations ongoing, do not refresh monitor - m_refresh = false; - } else { - m_refresh = true; - } -} -// virtual -void AddTransitionCommand::undo() -{ - if (m_remove) { - m_view->addTransition(m_info, m_track, m_params, m_refresh); - } else { - m_view->deleteTransition(m_info, m_track, m_params, m_refresh); - } -} -// virtual -void AddTransitionCommand::redo() -{ - if (m_doIt) { - if (m_remove) { - m_view->deleteTransition(m_info, m_track, m_params, m_refresh); - } else { - m_view->addTransition(m_info, m_track, m_params, m_refresh); - } - } - m_doIt = true; -} - -ChangeClipTypeCommand::ChangeClipTypeCommand(CustomTrackView *view, const ItemInfo &info, PlaylistState::ClipState state, - PlaylistState::ClipState originalState, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_info(info) - , m_state(state) - , m_originalState(originalState) -{ - setText(i18n("Change clip type")); -} -// virtual -void ChangeClipTypeCommand::undo() -{ - m_view->doChangeClipType(m_info, m_originalState); -} -// virtual -void ChangeClipTypeCommand::redo() -{ - m_view->doChangeClipType(m_info, m_state); -} - -ChangeEffectStateCommand::ChangeEffectStateCommand(CustomTrackView *view, const int track, const GenTime &pos, const QList &effectIndexes, bool disable, - bool refreshEffectStack, bool doIt, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_track(track) - , m_effectIndexes(effectIndexes) - , m_pos(pos) - , m_disable(disable) - , m_doIt(doIt) - , m_refreshEffectStack(refreshEffectStack) -{ - if (disable) { - setText(i18np("Disable effect", "Disable effects", effectIndexes.count())); - } else { - setText(i18np("Enable effect", "Enable effects", effectIndexes.count())); - } -} -// virtual -void ChangeEffectStateCommand::undo() -{ - m_view->updateEffectState(m_track, m_pos, m_effectIndexes, !m_disable, true); -} -// virtual -void ChangeEffectStateCommand::redo() -{ - if (m_doIt) { - m_view->updateEffectState(m_track, m_pos, m_effectIndexes, m_disable, m_refreshEffectStack); - } - m_doIt = true; - m_refreshEffectStack = true; -} - -ChangeSpeedCommand::ChangeSpeedCommand(CustomTrackView *view, const ItemInfo &info, const ItemInfo &speedIndependantInfo, PlaylistState::ClipState state, - double new_speed, int old_strobe, int new_strobe, const QString &clipId, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_clipInfo(info) - , m_speedIndependantInfo(speedIndependantInfo) - , m_state(state) - , m_clipId(clipId) - , m_new_speed(new_speed) - , m_old_strobe(old_strobe) - , m_new_strobe(new_strobe) -{ - setText(i18n("Adjust clip length")); -} -// virtual -void ChangeSpeedCommand::undo() -{ - m_view->doChangeClipSpeed(m_clipInfo, m_speedIndependantInfo, m_state, m_new_speed, m_old_strobe, m_clipId); -} -// virtual -void ChangeSpeedCommand::redo() -{ - m_view->doChangeClipSpeed(m_clipInfo, m_speedIndependantInfo, m_state, m_new_speed, m_new_strobe, m_clipId); -} - -ConfigTracksCommand::ConfigTracksCommand(Timeline *timeline, int track, const QString &oldName, const QString &newName, int oldState, int newState, - QUndoCommand *parent) - : QUndoCommand(parent) - , m_timeline(timeline) - , m_ix(track) - , m_oldName(oldName) - , m_newName(newName) - , m_oldState(oldState) - , m_newState(newState) -{ - setText(i18n("Configure Tracks")); -} -// virtual -void ConfigTracksCommand::undo() -{ - if (m_oldName != m_newName) { - m_timeline->renameTrack(m_ix, m_oldName); - } - if (m_oldState != m_newState) { - m_timeline->updateTrackState(m_ix, m_oldState); - } -} -// virtual -void ConfigTracksCommand::redo() -{ - if (m_oldName != m_newName) { - m_timeline->renameTrack(m_ix, m_newName); - } - if (m_oldState != m_newState) { - m_timeline->updateTrackState(m_ix, m_newState); - } -} - -EditEffectCommand::EditEffectCommand(CustomTrackView *view, const int track, const GenTime &pos, const QDomElement &oldeffect, const QDomElement &effect, - int stackPos, bool refreshEffectStack, bool doIt, bool refreshMonitor, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_track(track) - , m_oldeffect(oldeffect) - , m_effect(effect) - , m_pos(pos) - , m_stackPos(stackPos) - , m_doIt(doIt) - , m_refreshEffectStack(refreshEffectStack) - , m_replaceEffect(false) - , m_refreshMonitor(refreshMonitor) -{ - QString effectName; - QDomElement namenode = effect.firstChildElement(QStringLiteral("name")); - if (!namenode.isNull()) { - effectName = i18n(namenode.text().toUtf8().constData()); - } else { - effectName = i18n("effect"); - } - setText(i18n("Edit effect %1", effectName)); - if (m_effect.attribute(QStringLiteral("id")) == QLatin1String("pan_zoom")) { - QString bg = EffectsList::parameter(effect, QStringLiteral("background")); - QString oldBg = EffectsList::parameter(oldeffect, QStringLiteral("background")); - if (bg != oldBg) { - // effect needs a full reload - m_replaceEffect = true; - } - } -} -// virtual -int EditEffectCommand::id() const -{ - return 1; -} -// virtual -bool EditEffectCommand::mergeWith(const QUndoCommand *other) -{ - if (other->id() != id()) { - return false; - } - if (m_track != static_cast(other)->m_track) { - return false; - } - if (m_stackPos != static_cast(other)->m_stackPos) { - return false; - } - if (m_pos != static_cast(other)->m_pos) { - return false; - } - m_effect = static_cast(other)->m_effect.cloneNode().toElement(); - return true; -} -// virtual -void EditEffectCommand::undo() -{ - m_view->updateEffect(m_track, m_pos, m_oldeffect, true, m_replaceEffect, m_refreshMonitor); -} -// virtual -void EditEffectCommand::redo() -{ - if (m_doIt) { - m_view->updateEffect(m_track, m_pos, m_effect, m_refreshEffectStack, m_replaceEffect, m_refreshMonitor); - } - m_doIt = true; - m_refreshEffectStack = true; -} - -EditGuideCommand::EditGuideCommand(CustomTrackView *view, const GenTime &oldPos, const QString &oldcomment, const GenTime &pos, const QString &comment, - bool doIt, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_oldcomment(oldcomment) - , m_comment(comment) - , m_oldPos(oldPos) - , m_pos(pos) - , m_doIt(doIt) -{ - if (m_oldcomment.isEmpty()) { - setText(i18n("Add guide")); - m_oldPos = GenTime(-1); - } else if (m_oldPos == m_pos) { - setText(i18n("Edit guide")); - } else if (m_pos < GenTime() && m_comment.isEmpty()) { - setText(i18n("Delete guide")); - } else { - setText(i18n("Move guide")); - } -} -// virtual -void EditGuideCommand::undo() -{ - m_view->editGuide(m_pos, m_oldPos, m_oldcomment); -} -// virtual -void EditGuideCommand::redo() -{ - if (m_doIt) { - m_view->editGuide(m_oldPos, m_pos, m_comment); - } - m_doIt = true; -} - -EditTransitionCommand::EditTransitionCommand(CustomTrackView *view, const int track, const GenTime &pos, const QDomElement &oldeffect, - const QDomElement &effect, bool doIt, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_track(track) - , m_oldeffect(oldeffect) - , m_pos(pos) - , m_doIt(doIt) -{ - m_effect = effect.cloneNode().toElement(); - QString effectName; - QDomElement namenode = effect.firstChildElement(QStringLiteral("name")); - if (!namenode.isNull()) { - effectName = i18n(namenode.text().toUtf8().data()); - } else { - effectName = i18n("effect"); - } - setText(i18n("Edit transition %1", effectName)); -} -// virtual -int EditTransitionCommand::id() const -{ - return 2; -} -// virtual -bool EditTransitionCommand::mergeWith(const QUndoCommand *other) -{ - if (other->id() != id()) { - return false; - } - if (m_track != static_cast(other)->m_track) { - return false; - } - if (m_pos != static_cast(other)->m_pos) { - return false; - } - m_effect = static_cast(other)->m_effect; - return true; -} -// virtual -void EditTransitionCommand::undo() -{ - m_view->updateTransition(m_track, m_pos, m_effect, m_oldeffect, m_doIt); -} -// virtual -void EditTransitionCommand::redo() -{ - m_view->updateTransition(m_track, m_pos, m_oldeffect, m_effect, m_doIt); - m_doIt = true; -} - -GroupClipsCommand::GroupClipsCommand(CustomTrackView *view, const QList &clipInfos, const QList &transitionInfos, bool group, bool doIt, - QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_clips(clipInfos) - , m_transitions(transitionInfos) - , m_group(group) - , m_doIt(doIt) -{ - if (m_group) { - setText(i18n("Group clips")); - } else { - setText(i18n("Ungroup clips")); - } -} -// virtual -void GroupClipsCommand::undo() -{ - m_view->doGroupClips(m_clips, m_transitions, !m_group); -} -// virtual -void GroupClipsCommand::redo() -{ - if (m_doIt) { - m_view->doGroupClips(m_clips, m_transitions, m_group); - } - m_doIt = true; -} - -AddSpaceCommand::AddSpaceCommand(CustomTrackView *view, const ItemInfo &spaceInfo, const QList &excludeList, bool doIt, QUndoCommand *parent, - bool trackonly) - : QUndoCommand(parent) - , m_view(view) - , m_spaceInfo(spaceInfo) - , m_excludeList(excludeList) - , m_doIt(doIt) - , m_trackOnly(trackonly) -{ -} - -// virtual -void AddSpaceCommand::undo() -{ - m_view->insertTimelineSpace(m_spaceInfo.startPos, -m_spaceInfo.cropDuration, m_trackOnly ? m_spaceInfo.track : -1); -} -// virtual -void AddSpaceCommand::redo() -{ - if (m_doIt) { - m_view->insertTimelineSpace(m_spaceInfo.startPos, m_spaceInfo.cropDuration, m_trackOnly ? m_spaceInfo.track : -1, m_excludeList); - } - m_doIt = true; - m_excludeList.clear(); -} - -InsertSpaceCommand::InsertSpaceCommand(CustomTrackView *view, const QList &clipsToMove, const QList &transToMove, int track, - const GenTime &duration, bool doIt, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_clipsToMove(clipsToMove) - , m_transToMove(transToMove) - , m_duration(duration) - , m_track(track) - , m_doIt(doIt) -{ - if (duration > GenTime()) { - setText(i18n("Insert space")); - } else { - setText(i18n("Remove space")); - } -} -// virtual -void InsertSpaceCommand::undo() -{ - m_view->insertSpace(m_clipsToMove, m_transToMove, m_track, GenTime() - m_duration, m_duration); -} -// virtual -void InsertSpaceCommand::redo() -{ - if (m_doIt) { - m_view->insertSpace(m_clipsToMove, m_transToMove, m_track, m_duration, GenTime()); - } - m_doIt = true; -} - -LockTrackCommand::LockTrackCommand(CustomTrackView *view, int ix, bool lock, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_ix(ix) - , m_lock(lock) -{ - if (lock) { - setText(i18n("Lock track")); - } else { - setText(i18n("Unlock track")); - } -} -// virtual -void LockTrackCommand::undo() -{ - m_view->lockTrack(m_ix, !m_lock); -} -// virtual -void LockTrackCommand::redo() -{ - m_view->lockTrack(m_ix, m_lock); -} - -MoveClipCommand::MoveClipCommand(CustomTrackView *view, const ItemInfo &start, const ItemInfo &end, bool alreadyMoved, bool doIt, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_startPos(start) - , m_endPos(end) - , m_doIt(doIt) - , m_success(true) - , m_alreadyMoved(alreadyMoved) -{ - setText(i18n("Move clip")); - if (parent) { - // command has a parent, so there are several operations ongoing, do not refresh monitor - m_refresh = false; - } else { - m_refresh = true; - } -} - -void MoveClipCommand::undo() -{ - m_doIt = true; - // We can only undo what was done; - // if moveClip() failed in redo() the document does (or should) not change. - if (m_success) { - m_view->moveClip(m_endPos, m_startPos, m_refresh, false); - } -} -void MoveClipCommand::redo() -{ - if (m_doIt) { - // qCDebug(KDENLIVE_LOG) << "Executing move clip command. End now:" << m_endPos; - m_success = m_view->moveClip(m_startPos, m_endPos, m_refresh, m_alreadyMoved, &m_endPos); - // qCDebug(KDENLIVE_LOG) << "Move clip command executed. End now: " << m_endPos; - } - m_doIt = true; - m_alreadyMoved = false; -} - -MoveEffectCommand::MoveEffectCommand(CustomTrackView *view, const int track, const GenTime &pos, const QList &oldPos, int newPos, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_track(track) - , m_oldindex(oldPos) - , m_pos(pos) -{ - m_newindex.reserve(m_oldindex.count()); - for (int i = 0; i < m_oldindex.count(); ++i) { - m_newindex << newPos + i; - } - setText(i18n("Move effect")); -} -// virtual -int MoveEffectCommand::id() const -{ - return 2; -} -// virtual -bool MoveEffectCommand::mergeWith(const QUndoCommand *other) -{ - Q_UNUSED(other) - return false; -} -// virtual -void MoveEffectCommand::undo() -{ - m_view->moveEffect(m_track, m_pos, m_newindex, m_oldindex); -} -// virtual -void MoveEffectCommand::redo() -{ - m_view->moveEffect(m_track, m_pos, m_oldindex, m_newindex); -} - -MoveGroupCommand::MoveGroupCommand(CustomTrackView *view, const QList &startClip, const QList &startTransition, const GenTime &offset, - const int trackOffset, bool alreadyMoved, bool doIt, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_startClip(startClip) - , m_startTransition(startTransition) - , m_offset(offset) - , m_trackOffset(trackOffset) - , m_alreadyMoved(alreadyMoved) - , m_doIt(doIt) -{ - setText(i18n("Move group")); -} -// virtual -void MoveGroupCommand::undo() -{ - m_doIt = true; - m_view->moveGroup(m_startClip, m_startTransition, GenTime() - m_offset, -m_trackOffset, false, true); -} -// virtual -void MoveGroupCommand::redo() -{ - if (m_doIt) { - m_view->moveGroup(m_startClip, m_startTransition, m_offset, m_trackOffset, m_alreadyMoved, false); - } - m_doIt = true; - m_alreadyMoved = false; -} - -MoveTransitionCommand::MoveTransitionCommand(CustomTrackView *view, const ItemInfo &start, const ItemInfo &end, bool doIt, bool refresh, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_startPos(start) - , m_endPos(end) - , m_doIt(doIt) - , m_refresh(refresh) -{ - setText(i18n("Move transition")); -} -// virtual -void MoveTransitionCommand::undo() -{ - m_doIt = true; - m_view->moveTransition(m_endPos, m_startPos, m_refresh); -} -// virtual -void MoveTransitionCommand::redo() -{ - if (m_doIt) { - m_view->moveTransition(m_startPos, m_endPos, m_refresh); - } - m_doIt = true; -} - -RazorClipCommand::RazorClipCommand(CustomTrackView *view, const ItemInfo &info, const EffectsList &stack, const GenTime &cutTime, bool doIt, - QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_info(info) - , m_cutTime(cutTime) - , m_doIt(doIt) -{ - m_originalStack.clone(stack); - setText(i18n("Razor clip")); -} -// virtual -void RazorClipCommand::undo() -{ - m_view->cutClip(m_info, m_cutTime, false, m_originalStack); -} -// virtual -void RazorClipCommand::redo() -{ - if (m_doIt) { - m_view->cutClip(m_info, m_cutTime, true); - } - m_doIt = true; -} - -RazorTransitionCommand::RazorTransitionCommand(CustomTrackView *view, const ItemInfo &info, const QDomElement ¶ms, const GenTime &cutTime, bool doIt, - QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_info(info) - , m_cutTime(cutTime) - , m_doIt(doIt) -{ - m_originalParams = params.cloneNode(true).toElement(); - setText(i18n("Razor clip")); -} -// virtual -void RazorTransitionCommand::undo() -{ - m_view->cutTransition(m_info, m_cutTime, false, m_originalParams); -} -// virtual -void RazorTransitionCommand::redo() -{ - if (m_doIt) { - m_view->cutTransition(m_info, m_cutTime, true); - } - m_doIt = true; -} - -/* -RazorGroupCommand::RazorGroupCommand(CustomTrackView *view, QList clips1, QList transitions1, QList clipsCut, QList -transitionsCut, QList clips2, QList transitions2, GenTime cutPos, QUndoCommand * parent) : - QUndoCommand(parent), - m_view(view), - m_clips1(clips1), - m_transitions1(transitions1), - m_clipsCut(clipsCut), - m_transitionsCut(transitionsCut), - m_clips2(clips2), - m_transitions2(transitions2), - m_cutPos(cutPos) -{ - setText(i18n("Cut Group")); -} -// virtual -void RazorGroupCommand::undo() -{ - m_view->slotRazorGroup(m_clips1, m_transitions1, m_clipsCut, m_transitionsCut, m_clips2, m_transitions2, m_cutPos, false); -} -// virtual -void RazorGroupCommand::redo() -{ - m_view->slotRazorGroup(m_clips1, m_transitions1, m_clipsCut, m_transitionsCut, m_clips2, m_transitions2, m_cutPos, true); -} -*/ -RebuildGroupCommand::RebuildGroupCommand(CustomTrackView *view, int childTrack, const GenTime &childPos, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_childTrack(childTrack) - , m_childPos(childPos) -{ - setText(i18n("Rebuild Group")); -} -// virtual -void RebuildGroupCommand::undo() -{ - m_view->rebuildGroup(m_childTrack, m_childPos); -} -// virtual -void RebuildGroupCommand::redo() -{ - m_view->rebuildGroup(m_childTrack, m_childPos); -} - -RefreshMonitorCommand::RefreshMonitorCommand(CustomTrackView *view, const QList &info, bool execute, bool refreshOnUndo, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_info(info) - , m_exec(execute) - , m_execOnUndo(refreshOnUndo) -{ -} - -RefreshMonitorCommand::RefreshMonitorCommand(CustomTrackView *view, const ItemInfo &info, bool execute, bool refreshOnUndo, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_info(QList() << info) - , m_exec(execute) - , m_execOnUndo(refreshOnUndo) -{ -} - -// virtual -void RefreshMonitorCommand::undo() -{ - if (m_execOnUndo) { - m_view->monitorRefresh(m_info, true); - } -} -// virtual -void RefreshMonitorCommand::redo() -{ - if (m_exec && !m_execOnUndo) { - m_view->monitorRefresh(m_info, true); - } - m_exec = true; -} - -void RefreshMonitorCommand::updateRange(const QList &info) -{ - m_info.clear(); - m_info = info; -} - -ResizeClipCommand::ResizeClipCommand(CustomTrackView *view, const ItemInfo &start, const ItemInfo &end, bool doIt, bool dontWorry, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_startPos(start) - , m_endPos(end) - , m_doIt(doIt) - , m_dontWorry(dontWorry) -{ - setText(i18n("Resize clip")); -} -// virtual -void ResizeClipCommand::undo() -{ - m_view->resizeClip(m_endPos, m_startPos, m_dontWorry); -} -// virtual -void ResizeClipCommand::redo() -{ - if (m_doIt) { - m_view->resizeClip(m_startPos, m_endPos, m_dontWorry); - } - m_doIt = true; -} - -SplitAudioCommand::SplitAudioCommand(CustomTrackView *view, const int track, int destTrack, const GenTime &pos, QUndoCommand *parent) - : QUndoCommand(parent) - , m_view(view) - , m_pos(pos) - , m_track(track) - , m_destTrack(destTrack) - , m_success(false) -{ - setText(i18n("Split audio")); -} -// virtual -void SplitAudioCommand::undo() -{ - if (m_success) { - m_view->doSplitAudio(m_pos, m_track, m_destTrack, false); - } -} -// virtual -void SplitAudioCommand::redo() -{ - m_success = m_view->doSplitAudio(m_pos, m_track, m_destTrack, true); -} - -ChangeTrackStateCommand::ChangeTrackStateCommand(Timeline *timeline, const int track, bool changeAudio, bool changeVideo, bool hideAudio, bool hideVideo, - QUndoCommand *parent) - : QUndoCommand(parent) - , m_timeline(timeline) - , m_track(track) - , m_audio(changeAudio) - , m_video(changeVideo) - , m_hideAudio(hideAudio) - , m_hideVideo(hideVideo) -{ - setText(i18n("Change track state")); -} -// virtual -void ChangeTrackStateCommand::undo() -{ - if (m_audio) { - m_timeline->doSwitchTrackAudio(m_track, !m_hideAudio); - } - if (m_video) { - m_timeline->doSwitchTrackVideo(m_track, !m_hideVideo); - } -} -// virtual -void ChangeTrackStateCommand::redo() -{ - if (m_audio) { - m_timeline->doSwitchTrackAudio(m_track, m_hideAudio); - } - if (m_video) { - m_timeline->doSwitchTrackVideo(m_track, m_hideVideo); - } -} diff --git a/src/timeline/timelinecommands.h b/src/timeline/timelinecommands.h deleted file mode 100644 index da26cddc5..000000000 --- a/src/timeline/timelinecommands.h +++ /dev/null @@ -1,497 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2007-2012 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * Copyright (C) 2008 by Marco Gittler (g.marco@freenet.de) * - * Copyright (C) 2010 by Till Theato (root@ttill.de) * - * Copyright (C) 2014 by Vincent Pinon (vpinon@april.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TIMELINECOMMANDS_H -#define TIMELINECOMMANDS_H - -#include "definitions.h" -#include "effectslist/effectslist.h" -#include -#include -class GenTime; -class CustomTrackView; -class Timeline; - -class AddEffectCommand : public QUndoCommand -{ -public: - AddEffectCommand(CustomTrackView *view, const int track, const GenTime &pos, const QDomElement &effect, bool doIt, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - int m_track; - QDomElement m_effect; - GenTime m_pos; - bool m_doIt; -}; - -class AddTimelineClipCommand : public QUndoCommand -{ -public: - /** @brief Add clip in timeline. - * @param view The parent view - * @param clipId The Bin clip id - * @param info The position where to add clip - * @param effects the clip's effectStack - * @param state the clip's playlist state - * @param doIt whether to execute command on first run - * @param doRemove Should the clip be deleted or added on execute - * @param refreshMonitor Should the monitor be refreshed on execute (false if this command is in a group and - * refresh is executed separately - * @param parent The parent command - * */ - AddTimelineClipCommand(CustomTrackView *view, const QString &clipId, const ItemInfo &info, const EffectsList &effects, PlaylistState::ClipState state, - bool doIt, bool doRemove, bool refreshMonitor, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - QString m_clipId; - ItemInfo m_clipInfo; - EffectsList m_effects; - PlaylistState::ClipState m_state; - bool m_doIt; - bool m_remove; - bool m_refresh; -}; - -class AddTrackCommand : public QUndoCommand -{ -public: - AddTrackCommand(CustomTrackView *view, int ix, const TrackInfo &info, bool addTrack, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - int m_ix; - bool m_addTrack; - TrackInfo m_info; -}; - -class AddTransitionCommand : public QUndoCommand -{ -public: - AddTransitionCommand(CustomTrackView *view, const ItemInfo &info, int transitiontrack, const QDomElement ¶ms, bool remove, bool doIt, - QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - ItemInfo m_info; - QDomElement m_params; - int m_track; - bool m_doIt; - bool m_remove; - bool m_refresh; -}; - -class ChangeClipTypeCommand : public QUndoCommand -{ -public: - ChangeClipTypeCommand(CustomTrackView *view, const ItemInfo &info, PlaylistState::ClipState state, PlaylistState::ClipState originalState, - QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - ItemInfo m_info; - PlaylistState::ClipState m_state; - PlaylistState::ClipState m_originalState; -}; - -class ChangeEffectStateCommand : public QUndoCommand -{ -public: - ChangeEffectStateCommand(CustomTrackView *view, const int track, const GenTime &pos, const QList &effectIndexes, bool disable, bool refreshEffectStack, - bool doIt, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - const int m_track; - QList m_effectIndexes; - const GenTime m_pos; - bool m_disable; - bool m_doIt; - bool m_refreshEffectStack; -}; - -class ChangeSpeedCommand : public QUndoCommand -{ -public: - ChangeSpeedCommand(CustomTrackView *view, const ItemInfo &info, const ItemInfo &speedIndependantInfo, PlaylistState::ClipState state, double new_speed, - int old_strobe, int new_strobe, const QString &clipId, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - ItemInfo m_clipInfo; - ItemInfo m_speedIndependantInfo; - PlaylistState::ClipState m_state; - QString m_clipId; - double m_new_speed; - int m_old_strobe; - int m_new_strobe; -}; - -class ConfigTracksCommand : public QUndoCommand -{ -public: - ConfigTracksCommand(Timeline *timeline, int track, const QString &oldName, const QString &newName, int oldState = -1, int newState = -1, - QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - Timeline *m_timeline; - int m_ix; - QString m_oldName; - QString m_newName; - int m_oldState; - int m_newState; -}; - -class EditEffectCommand : public QUndoCommand -{ -public: - EditEffectCommand(CustomTrackView *view, const int track, const GenTime &pos, const QDomElement &oldeffect, const QDomElement &effect, int stackPos, - bool refreshEffectStack, bool doIt, bool refreshMonitor, QUndoCommand *parent = nullptr); - int id() const override; - bool mergeWith(const QUndoCommand *command) override; - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - const int m_track; - QDomElement m_oldeffect; - QDomElement m_effect; - const GenTime m_pos; - int m_stackPos; - bool m_doIt; - bool m_refreshEffectStack; - bool m_replaceEffect; - bool m_refreshMonitor; -}; - -class EditGuideCommand : public QUndoCommand -{ -public: - EditGuideCommand(CustomTrackView *view, const GenTime &oldPos, const QString &oldcomment, const GenTime &pos, const QString &comment, bool doIt, - QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - QString m_oldcomment; - QString m_comment; - GenTime m_oldPos; - GenTime m_pos; - bool m_doIt; -}; - -class EditTransitionCommand : public QUndoCommand -{ -public: - EditTransitionCommand(CustomTrackView *view, const int track, const GenTime &pos, const QDomElement &oldeffect, const QDomElement &effect, bool doIt, - QUndoCommand *parent = nullptr); - int id() const override; - bool mergeWith(const QUndoCommand *command) override; - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - const int m_track; - QDomElement m_effect; - QDomElement m_oldeffect; - const GenTime m_pos; - bool m_doIt; -}; - -class GroupClipsCommand : public QUndoCommand -{ -public: - GroupClipsCommand(CustomTrackView *view, const QList &clipInfos, const QList &transitionInfos, bool group, bool doIt = true, - QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - const QList m_clips; - const QList m_transitions; - bool m_group; - bool m_doIt; -}; - -class InsertSpaceCommand : public QUndoCommand -{ -public: - InsertSpaceCommand(CustomTrackView *view, const QList &clipsToMove, const QList &transToMove, int track, const GenTime &duration, - bool doIt, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - QList m_clipsToMove; - QList m_transToMove; - GenTime m_duration; - int m_track; - bool m_doIt; -}; - -class AddSpaceCommand : public QUndoCommand -{ -public: - AddSpaceCommand(CustomTrackView *view, const ItemInfo &spaceInfo, const QList &excludeList, bool doIt, QUndoCommand *parent = nullptr, - bool trackonly = false); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - ItemInfo m_spaceInfo; - QList m_excludeList; - bool m_doIt; - bool m_trackOnly; -}; - -class LockTrackCommand : public QUndoCommand -{ -public: - LockTrackCommand(CustomTrackView *view, int ix, bool lock, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - int m_ix; - bool m_lock; -}; - -class MoveClipCommand : public QUndoCommand -{ -public: - MoveClipCommand(CustomTrackView *view, const ItemInfo &start, const ItemInfo &end, bool alreadyMoved, bool doIt, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - const ItemInfo m_startPos; - ItemInfo m_endPos; - bool m_doIt; - bool m_refresh; - bool m_success; - bool m_alreadyMoved; -}; - -class MoveEffectCommand : public QUndoCommand -{ -public: - MoveEffectCommand(CustomTrackView *view, const int track, const GenTime &pos, const QList &oldPos, int newPos, QUndoCommand *parent = nullptr); - int id() const override; - bool mergeWith(const QUndoCommand *command) override; - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - int m_track; - QList m_oldindex; - QList m_newindex; - GenTime m_pos; -}; - -class MoveGroupCommand : public QUndoCommand -{ -public: - MoveGroupCommand(CustomTrackView *view, const QList &startClip, const QList &startTransition, const GenTime &offset, - const int trackOffset, bool alreadyMoved, bool doIt, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - const QList m_startClip; - const QList m_startTransition; - const GenTime m_offset; - const int m_trackOffset; - bool m_alreadyMoved; - bool m_doIt; -}; - -class MoveTransitionCommand : public QUndoCommand -{ -public: - MoveTransitionCommand(CustomTrackView *view, const ItemInfo &start, const ItemInfo &end, bool doIt, bool refresh, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - ItemInfo m_startPos; - ItemInfo m_endPos; - bool m_doIt; - bool m_refresh; -}; - -class RazorClipCommand : public QUndoCommand -{ -public: - RazorClipCommand(CustomTrackView *view, const ItemInfo &info, const EffectsList &stack, const GenTime &cutTime, bool doIt = true, - QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - ItemInfo m_info; - EffectsList m_originalStack; - GenTime m_cutTime; - bool m_doIt; -}; - -class RazorTransitionCommand : public QUndoCommand -{ -public: - RazorTransitionCommand(CustomTrackView *view, const ItemInfo &info, const QDomElement ¶ms, const GenTime &cutTime, bool doIt = true, - QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - ItemInfo m_info; - QDomElement m_originalParams; - GenTime m_cutTime; - bool m_doIt; -}; - -/* -class RazorGroupCommand : public QUndoCommand -{ -public: - RazorGroupCommand(CustomTrackView *view, QList clips1, QList transitions1, QList clipsCut, QList transitionsCut, -QList clips2, QList transitions2, GenTime cutPos, QUndoCommand * parent = nullptr); - virtual void undo(); - virtual void redo(); -private: - CustomTrackView *m_view; - QList m_clips1; - QList m_transitions1; - QList m_clipsCut; - QList m_transitionsCut; - QList m_clips2; - QList m_transitions2; - GenTime m_cutPos; -}; -*/ -class RebuildGroupCommand : public QUndoCommand -{ -public: - RebuildGroupCommand(CustomTrackView *view, int childTrack, const GenTime &childPos, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - int m_childTrack; - GenTime m_childPos; -}; - -class RefreshMonitorCommand : public QUndoCommand -{ -public: - RefreshMonitorCommand(CustomTrackView *view, const QList &info, bool execute, bool refreshOnUndo, QUndoCommand *parent = nullptr); - RefreshMonitorCommand(CustomTrackView *view, const ItemInfo &info, bool execute, bool refreshOnUndo, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - void updateRange(const QList &info); - -private: - CustomTrackView *m_view; - QList m_info; - bool m_exec; - bool m_execOnUndo; -}; - -class ResizeClipCommand : public QUndoCommand -{ -public: - ResizeClipCommand(CustomTrackView *view, const ItemInfo &start, const ItemInfo &end, bool doIt, bool dontWorry, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - ItemInfo m_startPos; - ItemInfo m_endPos; - bool m_doIt; - bool m_dontWorry; -}; - -class SplitAudioCommand : public QUndoCommand -{ -public: - SplitAudioCommand(CustomTrackView *view, const int track, const int destTrack, const GenTime &pos, QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - CustomTrackView *m_view; - const GenTime m_pos; - const int m_track; - const int m_destTrack; - // true if split command succeeded - bool m_success; -}; - -class ChangeTrackStateCommand : public QUndoCommand -{ -public: - ChangeTrackStateCommand(Timeline *timeline, const int track, bool changeAudio, bool changeVideo, bool hideAudio, bool hideVideo, - QUndoCommand *parent = nullptr); - void undo() override; - void redo() override; - -private: - Timeline *m_timeline; - const int m_track; - bool m_audio; - bool m_video; - bool m_hideAudio; - bool m_hideVideo; -}; - -#endif diff --git a/src/timeline/timelinesearch.cpp b/src/timeline/timelinesearch.cpp deleted file mode 100644 index 368b6562c..000000000 --- a/src/timeline/timelinesearch.cpp +++ /dev/null @@ -1,117 +0,0 @@ -/* -Copyright (C) 2010 Jean-Baptiste Mardelle -Copyright (C) 2014 Till Theato -This file is part of kdenlive. See www.kdenlive.org. - -This program 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 3 of the License, or -(at your option) any later version. -*/ - -#include "timelinesearch.h" -#include "core.h" -#include "customtrackview.h" -#include "mainwindow.h" -#include "project/projectmanager.h" - -#include "klocalizedstring.h" -#include - -TimelineSearch::TimelineSearch(QObject *parent) - : QObject(parent) -{ - connect(&m_searchTimer, &QTimer::timeout, this, &TimelineSearch::slotEndSearch); - m_searchTimer.setSingleShot(true); - - m_findAction = pCore->window()->addAction(QStringLiteral("project_find"), i18n("Find"), this, SLOT(slotInitSearch()), - QIcon::fromTheme(QStringLiteral("edit-find")), Qt::Key_Slash); - - m_findNextAction = pCore->window()->addAction(QStringLiteral("project_find_next"), i18n("Find Next"), this, SLOT(slotFindNext()), - QIcon::fromTheme(QStringLiteral("go-next")), Qt::Key_F3); - m_findNextAction->setEnabled(false); -} - -void TimelineSearch::slotInitSearch() -{ - m_findAction->setEnabled(false); - m_searchTerm.clear(); - pCore->projectManager()->currentTimeline()->projectView()->initSearchStrings(); - pCore->window()->statusBar()->showMessage(i18n("Starting -- find text as you type")); - m_searchTimer.start(5000); - qApp->installEventFilter(this); -} - -void TimelineSearch::slotEndSearch() -{ - m_searchTerm.clear(); - pCore->window()->statusBar()->showMessage(i18n("Find stopped"), 3000); - pCore->projectManager()->currentTimeline()->projectView()->clearSearchStrings(); - m_findNextAction->setEnabled(false); - m_findAction->setEnabled(true); - qApp->removeEventFilter(this); -} - -void TimelineSearch::slotFindNext() -{ - if (pCore->projectManager()->currentTimeline() && pCore->projectManager()->currentTimeline()->projectView()->findNextString(m_searchTerm)) { - pCore->window()->statusBar()->showMessage(i18n("Found: %1", m_searchTerm)); - } else { - pCore->window()->statusBar()->showMessage(i18n("Reached end of project")); - } - m_searchTimer.start(4000); -} - -void TimelineSearch::search() -{ - if (pCore->projectManager()->currentTimeline() && pCore->projectManager()->currentTimeline()->projectView()->findString(m_searchTerm)) { - m_findNextAction->setEnabled(true); - pCore->window()->statusBar()->showMessage(i18n("Found: %1", m_searchTerm)); - } else { - m_findNextAction->setEnabled(false); - pCore->window()->statusBar()->showMessage(i18n("Not found: %1", m_searchTerm)); - } -} - -bool TimelineSearch::eventFilter(QObject *watched, QEvent *event) -{ - // The ShortcutOverride event is emitted for every keyPressEvent, no matter if - // it is a registered shortcut or not. - - if (watched == pCore->window() && event->type() == QEvent::ShortcutOverride) { - - // Search, or pass event on if no search active or started - return keyPressEvent(static_cast(event)); - } - return QObject::eventFilter(watched, event); -} - -/** - * @return true, iff a search operation is in progress or started with the pressed key - */ -bool TimelineSearch::keyPressEvent(QKeyEvent *keyEvent) -{ - if (keyEvent->key() == Qt::Key_Backspace) { - m_searchTerm = m_searchTerm.left(m_searchTerm.length() - 1); - - if (m_searchTerm.isEmpty()) { - slotEndSearch(); - } else { - search(); - m_searchTimer.start(4000); - } - } else if (keyEvent->key() == Qt::Key_Escape) { - slotEndSearch(); - } else if (keyEvent->key() == Qt::Key_Space || !keyEvent->text().trimmed().isEmpty()) { - m_searchTerm += keyEvent->text(); - - search(); - - m_searchTimer.start(4000); - } else { - return false; - } - - keyEvent->accept(); - return true; -} diff --git a/src/timeline/timelinesearch.h b/src/timeline/timelinesearch.h deleted file mode 100644 index 432a6b8f9..000000000 --- a/src/timeline/timelinesearch.h +++ /dev/null @@ -1,54 +0,0 @@ -/* -Copyright (C) 2014 Till Theato -This file is part of kdenlive. See www.kdenlive.org. - -This program 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 3 of the License, or -(at your option) any later version. -*/ - -#ifndef TIMELINESEARCH_H -#define TIMELINESEARCH_H - -#include -#include - -class QAction; -class QKeyEvent; - -/** - * @class TimelineSearch - * @brief Provides functionality to search the timeline items (clips, guides) by name. - * - * Currently a part of the code remains in CustomTrackView. - * Should be made a plugin when refactoring is done. - */ - -class TimelineSearch : public QObject -{ - Q_OBJECT - -public: - explicit TimelineSearch(QObject *parent = nullptr); - -private slots: - void slotInitSearch(); - void slotEndSearch(); - void slotFindNext(); - -protected: - bool eventFilter(QObject *watched, QEvent *event) override; - -private: - void search(); - bool keyPressEvent(QKeyEvent *key); - - QAction *m_findAction; - QAction *m_findNextAction; - - QString m_searchTerm; - QTimer m_searchTimer; -}; - -#endif diff --git a/src/timeline/track.cpp b/src/timeline/track.cpp deleted file mode 100644 index c27a769c2..000000000 --- a/src/timeline/track.cpp +++ /dev/null @@ -1,1070 +0,0 @@ -/* - * Kdenlive timeline track handling MLT playlist - * Copyright 2015 Kdenlive team - * Author: Vincent Pinon - * - * This program 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) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * This program 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 this program. If not, see . - * - */ - -#include "track.h" -#include "clip.h" -#include "effectmanager.h" -#include "headertrack.h" -#include "kdenlivesettings.h" - -#include "kdenlive_debug.h" -#include - -Track::Track(int index, const QList &actions, Mlt::Playlist &playlist, TrackType trackType, int height, QWidget *parent) - : effectsList(EffectsList(true)) - , type(trackType) - , trackHeader(nullptr) - , m_index(index) - , m_playlist(playlist) -{ - QString playlist_name = playlist.get("id"); - if (playlist_name != QLatin1String("black_track")) { - trackHeader = new HeaderTrack(info(), actions, this, height, parent); - } -} - -Track::~Track() -{ - if (trackHeader) trackHeader->deleteLater(); -} - -// members access - -Mlt::Playlist &Track::playlist() -{ - return m_playlist; -} - -qreal Track::fps() -{ - return m_playlist.get_fps(); -} - -int Track::frame(qreal t) -{ - return round(t * fps()); -} - -qreal Track::length() -{ - return m_playlist.get_playtime() / fps(); -} - -// basic clip operations -bool Track::add(qreal t, Mlt::Producer *parent, qreal tcut, qreal dtcut, PlaylistState::ClipState state, bool duplicate, TimelineMode::EditMode mode) -{ - Mlt::Producer *cut = nullptr; - if (parent == nullptr || !parent->is_valid()) { - return false; - } - if (state == PlaylistState::Disabled) { - QScopedPointer prodCopy(Clip(*parent).clone()); - prodCopy->set("video_index", -1); - prodCopy->set("audio_index", -1); - prodCopy->set("kdenlive:binid", parent->get("id")); - cut = prodCopy->cut(frame(tcut), frame(dtcut) - 1); - } else if (duplicate && state != PlaylistState::VideoOnly) { - QScopedPointer newProd(clipProducer(parent, state)); - cut = newProd->cut(frame(tcut), frame(dtcut) - 1); - } else { - cut = parent->cut(frame(tcut), frame(dtcut) - 1); - } - if (parent->is_cut()) { - Clip(*cut).addEffects(*parent); - } - m_playlist.lock(); - bool result = doAdd(t, cut, mode); - m_playlist.unlock(); - delete cut; - return result; -} - -bool Track::doAdd(qreal t, Mlt::Producer *cut, TimelineMode::EditMode mode) -{ - int pos = frame(t); - if (pos < m_playlist.get_playtime() && mode == TimelineMode::InsertEdit) { - m_playlist.split_at(pos); - } - m_playlist.consolidate_blanks(); - if (m_playlist.insert_at(pos, cut, 1) == m_playlist.count() - 1) { - emit newTrackDuration(m_playlist.get_playtime()); - } - return true; -} - -bool Track::move(qreal start, qreal end, TimelineMode::EditMode mode) -{ - int pos = frame(start); - m_playlist.lock(); - int clipIndex = m_playlist.get_clip_index_at(pos); - bool durationChanged = false; - if (clipIndex == m_playlist.count() - 1) { - durationChanged = true; - } - QScopedPointer clipProducer(m_playlist.replace_with_blank(clipIndex)); - if (!clipProducer || clipProducer->is_blank()) { - qCDebug(KDENLIVE_LOG) << "// Cannot get clip at index: " << clipIndex << " / " << start; - m_playlist.unlock(); - return false; - } - m_playlist.consolidate_blanks(); - if (end >= m_playlist.get_playtime()) { - // Clip is inserted at the end of track, duration change event handled in doAdd() - durationChanged = false; - } - bool result = doAdd(end, clipProducer.data(), mode); - m_playlist.unlock(); - if (durationChanged) { - emit newTrackDuration(m_playlist.get_playtime()); - } - return result; -} - -bool Track::isLastClip(qreal t) -{ - int clipIndex = m_playlist.get_clip_index_at(frame(t)); - return clipIndex >= m_playlist.count() - 1; -} - -bool Track::del(qreal t, bool checkDuration) -{ - m_playlist.lock(); - bool durationChanged = false; - int pos = frame(t); - int ix = m_playlist.get_clip_index_at(pos); - if (ix == m_playlist.count() - 1) { - durationChanged = true; - } - Mlt::Producer *clip = m_playlist.replace_with_blank(ix); - if (clip) { - delete clip; - } else { - qWarning("Error deleting clip at %d, tk: %d", pos, m_index); - m_playlist.unlock(); - return false; - } - m_playlist.consolidate_blanks(); - m_playlist.unlock(); - if (durationChanged && checkDuration) { - emit newTrackDuration(m_playlist.get_playtime()); - } - return true; -} - -bool Track::del(qreal t, qreal dt) -{ - m_playlist.lock(); - m_playlist.insert_blank(m_playlist.remove_region(frame(t), frame(dt) + 1), frame(dt)); - m_playlist.consolidate_blanks(); - m_playlist.unlock(); - return true; -} - -bool Track::resize(qreal t, qreal dt, bool end) -{ - m_playlist.lock(); - int startFrame = frame(t); - int index = m_playlist.get_clip_index_at(startFrame); - int length = frame(dt); - QScopedPointer clip(m_playlist.get_clip(index)); - if (clip == nullptr || clip->is_blank()) { - qWarning("Can't resize clip at %f", t); - m_playlist.unlock(); - return false; - } - - int in = clip->get_in(); - int out = clip->get_out(); - if (end) { - // Resizing clip end - startFrame += out - in; - out += length; - } else { - // Resizing clip start - in += length; - } - - // image or color clips are not bounded - if (in < 0) { - out -= in; - in = 0; - } - if (clip->get_length() < out + 1) { - clip->parent().set("length", out + 2); - clip->parent().set("out", out + 1); - clip->set("length", out + 2); - } - - if (m_playlist.resize_clip(index, in, out) != 0) { - qWarning("MLT resize failed : clip %d from %d to %d", index, in, out); - m_playlist.unlock(); - return false; - } - - // adjust adjacent blank - if (end) { - ++index; - if (index > m_playlist.count() - 1) { - m_playlist.unlock(); - // this is the last clip in track, check tracks length to adjust black track and project duration - emit newTrackDuration(m_playlist.get_playtime()); - return true; - } - length = -length; - } - if (length > 0) { // reducing clip - m_playlist.insert_blank(index, length - 1); - } else { - if (!end) --index; - if (!m_playlist.is_blank(index)) { - qWarning("Resizing over non-blank clip %d!", index); - } - out = m_playlist.clip_length(index) + length - 1; - if (out >= 0) { - if (m_playlist.resize_clip(index, 0, out) != 0) { - qWarning("Error resizing blank %d", index); - } - } else { - if (m_playlist.remove(index) != 0) { - qWarning("Error removing blank %d", index); - } - } - } - - m_playlist.consolidate_blanks(); - m_playlist.unlock(); - return true; -} - -bool Track::cut(qreal t) -{ - int pos = frame(t); - m_playlist.lock(); - int index = m_playlist.get_clip_index_at(pos); - if (m_playlist.is_blank(index)) { - qCDebug(KDENLIVE_LOG) << " - - --Warning, clip is blank at: " << index; - m_playlist.unlock(); - return false; - } - if (m_playlist.split(index, pos - m_playlist.clip_start(index) - 1) != 0) { - qWarning("MLT split failed"); - m_playlist.unlock(); - return false; - } - m_playlist.unlock(); - QScopedPointer clip1(m_playlist.get_clip(index)); - QScopedPointer clip2(m_playlist.get_clip(index + 1)); - qCDebug(KDENLIVE_LOG) << "CLIP CUT ID: " << clip1->get("id") << " / " << clip1->parent().get("id"); - Clip(*clip2).addEffects(*clip1, true); - for (int i = 0; i < clip1->filter_count(); ++i) { - QString effectId = clip1->filter(i)->get("kdenlive_id"); - if (effectId == "fadeout" || effectId == "fade_to_black") { - Mlt::Filter *f = clip1->filter(i); - clip1->detach(*f); - delete f; - --i; - } - } - // adjust filters in/out - Clip(*clip1).adjustEffectsLength(); - return true; -} - -bool Track::needsDuplicate(const QString &service) const -{ - return (service.contains(QStringLiteral("avformat")) || service.contains(QStringLiteral("consumer")) || service.contains(QStringLiteral("xml"))); -} - -void Track::lockTrack(bool locked) -{ - if (!trackHeader) return; - setProperty(QStringLiteral("kdenlive:locked_track"), locked ? 1 : 0); - trackHeader->setLock(locked); -} - -void Track::replaceId(const QString &id) -{ - QString idForAudioTrack = id + QLatin1Char('_') + m_playlist.get("id") + QStringLiteral("_audio"); - QString idForVideoTrack = id + QStringLiteral("_video"); - QString idForTrack = id + QLatin1Char('_') + m_playlist.get("id"); - // TODO: slowmotion - for (int i = 0; i < m_playlist.count(); i++) { - if (m_playlist.is_blank(i)) continue; - QScopedPointer p(m_playlist.get_clip(i)); - QString current = p->parent().get("id"); - if (current == id || current == idForTrack || current == idForAudioTrack || current == idForVideoTrack || - current.startsWith("slowmotion:" + id + QLatin1Char(':'))) { - current.prepend(QLatin1Char('#')); - p->parent().set("id", current.toUtf8().constData()); - } - } -} - -QList Track::getSlowmotionInfos(const QString &id) -{ - QList list; - QLocale locale; - for (int i = 0; i < m_playlist.count(); i++) { - if (m_playlist.is_blank(i)) continue; - QScopedPointer p(m_playlist.get_clip(i)); - QString current = p->parent().get("id"); - if (!current.startsWith(QLatin1Char('#'))) { - continue; - } - current.remove(0, 1); - if (current.startsWith("slowmotion:" + id + QLatin1Char(':'))) { - Track::SlowmoInfo info; - info.readFromString(current.section(QLatin1Char(':'), 2), locale); - list << info; - } - } - return list; -} - -QList Track::replaceAll(const QString &id, Mlt::Producer *original, Mlt::Producer *videoOnlyProducer, - const QMap &newSlowMos) -{ - QString idForAudioTrack; - QString idForVideoTrack; - QString service = original->parent().get("mlt_service"); - QString idForTrack = original->parent().get("id"); - int tkState = state(); - if (needsDuplicate(service)) { - // We have to use the track clip duplication functions, because of audio glitches in MLT's multitrack - idForAudioTrack = idForTrack + QLatin1Char('_') + m_playlist.get("id") + QStringLiteral("_audio"); - idForVideoTrack = idForTrack + QStringLiteral("_video"); - idForTrack.append(QLatin1Char('_') + m_playlist.get("id")); - } - Mlt::Producer *trackProducer = nullptr; - Mlt::Producer *audioTrackProducer = nullptr; - QList replaced; - for (int i = 0; i < m_playlist.count(); i++) { - if (m_playlist.is_blank(i)) continue; - QScopedPointer p(m_playlist.get_clip(i)); - QString current = p->parent().get("id"); - if (current == id) { - if (((tkState & 1) != 0) || - (QString(p->parent().get("mlt_service")).contains(QStringLiteral("avformat")) && p->parent().get_int("video_index") == -1)) { - // Video is hidden, nothing visible - continue; - } - // master clip used, only notify for update - ItemInfo cInfo; - cInfo.startPos = GenTime(m_playlist.clip_start(i), fps()); - cInfo.endPos = cInfo.startPos + GenTime(m_playlist.clip_length(i), fps()); - cInfo.track = m_index; - replaced << cInfo; - continue; - } - if (!current.startsWith(QLatin1Char('#'))) { - continue; - } - current.remove(0, 1); - Mlt::Producer *cut = nullptr; - if (current.startsWith("slowmotion:" + id + QLatin1Char(':'))) { - // Slowmotion producer, just update resource - Mlt::Producer *slowProd = newSlowMos.value(current.section(QLatin1Char(':'), 2)); - if ((slowProd == nullptr) || !slowProd->is_valid()) { - qCDebug(KDENLIVE_LOG) << "/// WARNING, couldn't find replacement slowmo for " << id; - continue; - } - cut = slowProd->cut(p->get_in(), p->get_out()); - } - if ((cut == nullptr) && idForAudioTrack.isEmpty()) { - if (current == idForTrack) { - // No duplication required - cut = original->cut(p->get_in(), p->get_out()); - } else if (!idForTrack.contains(QLatin1Char('_')) && idForTrack == current.section(QLatin1Char('_'), 0, 0)) { - // Unproxying a slideshow - cut = original->cut(p->get_in(), p->get_out()); - } else { - continue; - } - } - if ((cut == nullptr) && p->parent().get_int("audio_index") == -1 && current == id) { - // No audio - no duplication required - cut = original->cut(p->get_in(), p->get_out()); - } else if ((cut == nullptr) && - ((current == idForTrack) || (!current.contains(QLatin1Char('_')) && current == idForTrack.section(QLatin1Char('_'), 0, 0)))) { - // Use duplicate - if (trackProducer == nullptr) { - if (idForTrack.contains(QLatin1Char('_'))) { - trackProducer = Clip(*original).clone(); - trackProducer->set("id", idForTrack.toUtf8().constData()); - } - } - cut = trackProducer->cut(p->get_in(), p->get_out()); - } else if ((cut == nullptr) && current == idForAudioTrack) { - if (audioTrackProducer == nullptr) { - audioTrackProducer = clipProducer(original, PlaylistState::AudioOnly, true); - } - cut = audioTrackProducer->cut(p->get_in(), p->get_out()); - } else if ((cut == nullptr) && current == idForVideoTrack) { - cut = videoOnlyProducer->cut(p->get_in(), p->get_out()); - } - if (cut) { - Clip(*cut).addEffects(*p); - ItemInfo cInfo; - cInfo.startPos = GenTime(m_playlist.clip_start(i), fps()); - cInfo.endPos = cInfo.startPos + GenTime(m_playlist.clip_length(i), fps()); - m_playlist.remove(i); - m_playlist.insert(*cut, i); - m_playlist.consolidate_blanks(); - delete cut; - if (((tkState & 1) != 0) || - (QString(p->parent().get("mlt_service")).contains(QStringLiteral("avformat")) && p->parent().get_int("video_index") == -1)) { - // Video is hidden for this track, nothing visible - continue; - } - cInfo.track = m_index; - replaced << cInfo; - } - } - delete trackProducer; - delete audioTrackProducer; - return replaced; -} - -// TODO: cut: checkSlowMotionProducer -bool Track::replace(qreal t, Mlt::Producer *prod, PlaylistState::ClipState state, PlaylistState::ClipState originalState) -{ - m_playlist.lock(); - int index = m_playlist.get_clip_index_at(frame(t)); - Mlt::Producer *cut; - QScopedPointer orig(m_playlist.replace_with_blank(index)); - QString service = prod->get("mlt_service"); - if (state == PlaylistState::Disabled) { - QScopedPointer prodCopy(Clip(*prod).clone()); - // Reset id to let MLT give a new one - prodCopy->set("id", (char *)nullptr); - prodCopy->set("video_index", -1); - prodCopy->set("audio_index", -1); - prodCopy->set("kdenlive:binid", prod->get("id")); - prodCopy->set("kdenlive:clipstate", (int)originalState); - cut = prodCopy->cut(orig->get_in(), orig->get_out()); - } else if (state != PlaylistState::VideoOnly && service != QLatin1String("timewarp")) { - // Get track duplicate - Mlt::Producer *copyProd = clipProducer(prod, state); - cut = copyProd->cut(orig->get_in(), orig->get_out()); - delete copyProd; - } else { - cut = prod->cut(orig->get_in(), orig->get_out()); - } - Clip(*cut).addEffects(*orig); - bool ok = m_playlist.insert_at(frame(t), cut, 1) >= 0; - delete cut; - m_playlist.unlock(); - return ok; -} - -void Track::updateEffects(const QString &id, Mlt::Producer *original) -{ - QString idForAudioTrack; - QString idForVideoTrack; - QString service = original->parent().get("mlt_service"); - QString idForTrack = original->parent().get("id"); - if (needsDuplicate(service)) { - // We have to use the track clip duplication functions, because of audio glitches in MLT's multitrack - idForAudioTrack = idForTrack + QLatin1Char('_') + m_playlist.get("id") + QStringLiteral("_audio"); - idForVideoTrack = idForTrack + QStringLiteral("_video"); - idForTrack.append(QLatin1Char('_') + m_playlist.get("id")); - } - - for (int i = 0; i < m_playlist.count(); i++) { - if (m_playlist.is_blank(i)) continue; - QScopedPointer p(m_playlist.get_clip(i)); - Mlt::Producer origin = p->parent(); - QString current = origin.get("id"); - if (current.startsWith(QLatin1String("slowmotion:"))) { - if (current.section(QLatin1Char(':'), 1, 1) == id) { - Clip(origin).replaceEffects(*original); - } - } else if (current == id) { - // we are directly using original producer, no need to update effects - continue; - } else if (current.section(QLatin1Char('_'), 0, 0) == id) { - Clip(origin).replaceEffects(*original); - } - } -} - -/*Mlt::Producer &Track::find(const QByteArray &name, const QByteArray &value, int startindex) { - for (int i = startindex; i < m_playlist.count(); i++) { - if (m_playlist.is_blank(i)) continue; - QScopedPointer p(m_playlist.get_clip(i)); - if (value == p->parent().get(name.constData())) { - return p->parent(); - } - } - return Mlt::0; -}*/ - -Mlt::Producer *Track::clipProducer(Mlt::Producer *parent, PlaylistState::ClipState state, bool forceCreation) -{ - QString service = parent->parent().get("mlt_service"); - QString originalId = parent->parent().get("id"); - if (!needsDuplicate(service) || state == PlaylistState::VideoOnly || originalId.endsWith(QLatin1String("_video"))) { - // Don't clone producer for track if it has no audio - return new Mlt::Producer(*parent); - } - originalId = originalId.section(QLatin1Char('_'), 0, 0); - QString idForTrack = originalId + QLatin1Char('_') + m_playlist.get("id"); - if (state == PlaylistState::AudioOnly) { - idForTrack.append(QStringLiteral("_audio")); - } - if (!forceCreation) { - for (int i = 0; i < m_playlist.count(); i++) { - if (m_playlist.is_blank(i)) continue; - QScopedPointer p(m_playlist.get_clip(i)); - if (QString(p->parent().get("id")) == idForTrack) { - return new Mlt::Producer(p->parent()); - } - } - } - Mlt::Producer *prod = Clip(parent->parent()).clone(); - prod->set("id", idForTrack.toUtf8().constData()); - if (state == PlaylistState::AudioOnly) { - prod->set("video_index", -1); - } - return prod; -} - -bool Track::hasAudio() -{ - for (int i = 0; i < m_playlist.count(); i++) { - if (m_playlist.is_blank(i)) continue; - QScopedPointer p(m_playlist.get_clip(i)); - QString service = p->get("mlt_service"); - if (service == QLatin1String("xml") || service == QLatin1String("consumer") || p->get_int("audio_index") > -1) { - return true; - } - } - return false; -} - -void Track::setProperty(const QString &name, const QString &value) -{ - m_playlist.set(name.toUtf8().constData(), value.toUtf8().constData()); -} - -void Track::setProperty(const QString &name, int value) -{ - m_playlist.set(name.toUtf8().constData(), value); -} - -const QString Track::getProperty(const QString &name) -{ - return QString(m_playlist.get(name.toUtf8().constData())); -} - -int Track::getIntProperty(const QString &name) -{ - return m_playlist.get_int(name.toUtf8().constData()); -} - -TrackInfo Track::info() -{ - TrackInfo info; - info.trackName = m_playlist.get("kdenlive:track_name"); - info.isLocked = (m_playlist.get_int("kdenlive:locked_track") != 0); - int currentState = m_playlist.parent().get_int("hide"); - info.isMute = ((currentState & 2) != 0); - info.isBlind = ((currentState & 1) != 0); - info.type = type; - info.effectsList = effectsList; - info.duration = m_playlist.get_length(); - return info; -} - -void Track::setInfo(const TrackInfo &info) -{ - if (!trackHeader) return; - m_playlist.set("kdenlive:track_name", info.trackName.toUtf8().constData()); - m_playlist.set("kdenlive:locked_track", info.isLocked ? 1 : 0); - int state = 0; - if (info.isMute) { - if (info.isBlind) - state = 3; - else - state = 2; - } else if (info.isBlind) - state = 1; - m_playlist.parent().set("hide", state); - type = info.type; - trackHeader->updateStatus(info); -} - -int Track::state() -{ - return m_playlist.parent().get_int("hide"); -} - -void Track::setState(int state) -{ - m_playlist.parent().set("hide", state); -} - -int Track::getBlankLength(int pos, bool fromBlankStart) -{ - int clipIndex = m_playlist.get_clip_index_at(pos); - if (clipIndex == m_playlist.count()) { - // We are after the end of the playlist - return -1; - } - if (!m_playlist.is_blank(clipIndex)) return 0; - if (fromBlankStart) return m_playlist.clip_length(clipIndex); - return m_playlist.clip_length(clipIndex) + m_playlist.clip_start(clipIndex) - pos; -} - -void Track::updateClipProperties(const QString &id, const QMap &properties) -{ - QString idForTrack = id + QLatin1Char('_') + m_playlist.get("id"); - QString idForVideoTrack = id + QStringLiteral("_video"); - QString idForAudioTrack = idForTrack + QStringLiteral("_audio"); - // slowmotion producers are updated in renderer - - for (int i = 0; i < m_playlist.count(); i++) { - if (m_playlist.is_blank(i)) continue; - QScopedPointer p(m_playlist.get_clip(i)); - QString current = p->parent().get("id"); - QStringList processed; - if (!processed.contains(current) && (current == idForTrack || current == idForAudioTrack || current == idForVideoTrack)) { - QMapIterator j(properties); - while (j.hasNext()) { - j.next(); - p->parent().set(j.key().toUtf8().constData(), j.value().toUtf8().constData()); - } - processed << current; - } - } -} - -Mlt::Producer *Track::buildSlowMoProducer(Mlt::Properties passProps, const QString &url, const QString &id, Track::SlowmoInfo info) -{ - QLocale locale; - Mlt::Producer *prod = new Mlt::Producer(*m_playlist.profile(), nullptr, ("timewarp:" + url).toUtf8().constData()); - if (!prod->is_valid()) { - qCDebug(KDENLIVE_LOG) << "++++ FAILED TO CREATE SLOWMO PROD"; - return nullptr; - } - QString producerid = "slowmotion:" + id + QLatin1Char(':') + info.toString(locale); - prod->set("id", producerid.toUtf8().constData()); - - // copy producer props - for (int i = 0; i < passProps.count(); i++) { - prod->set(passProps.get_name(i), passProps.get(i)); - } - // set clip state - switch ((int)info.state) { - case PlaylistState::VideoOnly: - prod->set("audio_index", -1); - break; - case PlaylistState::AudioOnly: - prod->set("video_index", -1); - break; - default: - break; - } - QString slowmoId = info.toString(locale); - slowmoId.append(prod->get("warp_resource")); - emit storeSlowMotion(slowmoId, prod); - return prod; -} - -int Track::changeClipSpeed(const ItemInfo &info, const ItemInfo &speedIndependantInfo, PlaylistState::ClipState state, double speed, int strobe, - Mlt::Producer *prod, const QString &id, Mlt::Properties passProps, bool removeEffect) -{ - // TODO: invalidate preview rendering - int newLength = 0; - int startPos = info.startPos.frames(fps()); - int clipIndex = m_playlist.get_clip_index_at(startPos); - int clipLength = m_playlist.clip_length(clipIndex); - m_playlist.lock(); - QScopedPointer original(m_playlist.get_clip(clipIndex)); - if (original == nullptr) { - qCDebug(KDENLIVE_LOG) << "// No clip to apply effect"; - m_playlist.unlock(); - return -1; - } - if (!original->is_valid() || original->is_blank()) { - // invalid clip - qCDebug(KDENLIVE_LOG) << "// Invalid clip to apply effect"; - m_playlist.unlock(); - return -1; - } - Mlt::Producer clipparent = original->parent(); - if (!clipparent.is_valid() || clipparent.is_blank()) { - // invalid clip - qCDebug(KDENLIVE_LOG) << "// Invalid parent to apply effect"; - m_playlist.unlock(); - return -1; - } - QLocale locale; - if (speed <= 0 && speed > -1) speed = 1.0; - QString serv = clipparent.get("mlt_service"); - QString url; - if (serv == QLatin1String("timewarp")) { - url = QString::fromUtf8(clipparent.get("warp_resource")); - } else { - url = QString::fromUtf8(clipparent.get("resource")); - } - url.prepend(locale.toString(speed) + QLatin1Char(':')); - Track::SlowmoInfo slowInfo; - slowInfo.speed = speed; - slowInfo.strobe = strobe; - slowInfo.state = state; - if (serv.contains(QStringLiteral("avformat"))) { - if (speed != 1.0 || strobe > 1) { - if ((prod == nullptr) || !prod->is_valid()) { - prod = buildSlowMoProducer(passProps, url, id, slowInfo); - if (prod == nullptr) { - // error, abort - qCDebug(KDENLIVE_LOG) << "++++ FAILED TO CREATE SLOWMO PROD"; - m_playlist.unlock(); - return -1; - } - } - QScopedPointer clip(m_playlist.replace_with_blank(clipIndex)); - m_playlist.consolidate_blanks(0); - - // Check that the blank space is long enough for our new duration - clipIndex = m_playlist.get_clip_index_at(startPos); - int blankEnd = m_playlist.clip_start(clipIndex) + m_playlist.clip_length(clipIndex); - Mlt::Producer *cut; - if (clipIndex + 1 < m_playlist.count() && (startPos + clipLength / speed > blankEnd)) { - GenTime maxLength = GenTime(blankEnd, fps()) - info.startPos; - cut = prod->cut((int)(info.cropStart.frames(fps()) / speed), (int)(info.cropStart.frames(fps()) / speed + maxLength.frames(fps()) - 1)); - } else - cut = prod->cut((int)(info.cropStart.frames(fps()) / speed), (int)((info.cropStart.frames(fps()) + clipLength) / speed - 1)); - - // move all effects to the correct producer - Clip(*cut).addEffects(*clip); - m_playlist.insert_at(startPos, cut, 1); - delete cut; - clipIndex = m_playlist.get_clip_index_at(startPos); - newLength = m_playlist.clip_length(clipIndex); - } else if (speed == 1.0 && strobe < 2) { - QScopedPointer clip(m_playlist.replace_with_blank(clipIndex)); - m_playlist.consolidate_blanks(0); - - // Check that the blank space is long enough for our new duration - clipIndex = m_playlist.get_clip_index_at(startPos); - int blankEnd = m_playlist.clip_start(clipIndex) + m_playlist.clip_length(clipIndex); - - Mlt::Producer *cut; - - if ((prod == nullptr) || !prod->is_valid()) { - prod = buildSlowMoProducer(passProps, url, id, slowInfo); - if (prod == nullptr) { - // error, abort - qCDebug(KDENLIVE_LOG) << "++++ FAILED TO CREATE SLOWMO PROD"; - m_playlist.unlock(); - return -1; - } - } - - int originalStart = (int)(speedIndependantInfo.cropStart.frames(fps())); - if (clipIndex + 1 < m_playlist.count() && (info.startPos + speedIndependantInfo.cropDuration).frames(fps()) > blankEnd) { - GenTime maxLength = GenTime(blankEnd, fps()) - info.startPos; - cut = prod->cut(originalStart, (int)(originalStart + maxLength.frames(fps()) - 1)); - } else { - cut = prod->cut(originalStart, (int)(originalStart + speedIndependantInfo.cropDuration.frames(fps())) - 1); - } - - // move all effects to the correct producer - Clip(*cut).addEffects(*clip); - m_playlist.insert_at(startPos, cut, 1); - delete cut; - clipIndex = m_playlist.get_clip_index_at(startPos); - newLength = m_playlist.clip_length(clipIndex); - } - } else if (serv == QLatin1String("timewarp")) { - if ((prod == nullptr) || !prod->is_valid()) { - prod = buildSlowMoProducer(passProps, url, id, slowInfo); - if (prod == nullptr) { - // error, abort - qCDebug(KDENLIVE_LOG) << "++++ FAILED TO CREATE SLOWMO PROD"; - m_playlist.unlock(); - return -1; - } - } - if (removeEffect) { - prod = clipProducer(prod, state); - } - QScopedPointer clip(m_playlist.replace_with_blank(clipIndex)); - m_playlist.consolidate_blanks(0); - int duration; - int originalStart; - if (speed == 1.0) { - duration = speedIndependantInfo.cropDuration.frames(fps()); - originalStart = speedIndependantInfo.cropStart.frames(fps()); - } else { - duration = qMax(2, qAbs((int)(speedIndependantInfo.cropDuration.frames(fps()) / speed + 0.5))); - originalStart = (int)(speedIndependantInfo.cropStart.frames(fps()) / speed + 0.5); - } - // qCDebug(KDENLIVE_LOG)<<"/ / /UPDATE SPEED: "< blankEnd) { - outPos = originalStart + (blankEnd - startPos); - } - } - // Last clip in playlist, no duration limit - cut = prod->cut(originalStart, outPos); - // move all effects to the correct producer - Clip(*cut).addEffects(*clip); - m_playlist.insert_at(startPos, cut, 1); - delete cut; - clipIndex = m_playlist.get_clip_index_at(startPos); - newLength = m_playlist.clip_length(clipIndex); - if (removeEffect) delete prod; - } - // Do not delete prod, it is now stored in the slowmotion producers list - m_playlist.unlock(); - if (clipIndex + 1 == m_playlist.count()) { - // We changed the speed of last clip in playlist, check track length - emit newTrackDuration(m_playlist.get_playtime()); - } - return newLength; -} - -int Track::index() const -{ - return m_index; -} - -int Track::spaceLength(int pos, bool fromBlankStart) -{ - int clipIndex = m_playlist.get_clip_index_at(pos); - if (clipIndex == m_playlist.count()) { - // We are after the end of the playlist - return -1; - } - if (!m_playlist.is_blank(clipIndex)) return 0; - if (fromBlankStart) return m_playlist.clip_length(clipIndex); - return m_playlist.clip_length(clipIndex) + m_playlist.clip_start(clipIndex) - pos; -} - -void Track::disableEffects(bool disable) -{ - // Disable track effects - enableTrackEffects(QList(), disable, true); - // Disable timeline clip effects - for (int i = 0; i < m_playlist.count(); i++) { - QScopedPointer original(m_playlist.get_clip(i)); - if (original == nullptr || !original->is_valid() || original->is_blank()) { - // invalid clip - continue; - } - Clip(*original).disableEffects(disable); - } -} - -bool Track::addEffect(double start, const EffectsParameterList ¶ms) -{ - int pos = frame(start); - int clipIndex = m_playlist.get_clip_index_at(pos); - int duration = m_playlist.clip_length(clipIndex); - QScopedPointer clip(m_playlist.get_clip(clipIndex)); - if (!clip) { - return false; - } - Mlt::Service clipService(clip->get_service()); - EffectManager effect(clipService); - return effect.addEffect(params, duration); -} - -bool Track::addTrackEffect(const EffectsParameterList ¶ms) -{ - Mlt::Service trackService(m_playlist.get_service()); - EffectManager effect(trackService); - int duration = m_playlist.get_playtime() - 1; - return effect.addEffect(params, duration); -} - -bool Track::editEffect(double start, const EffectsParameterList ¶ms, bool replace) -{ - int pos = frame(start); - int clipIndex = m_playlist.get_clip_index_at(pos); - int duration = m_playlist.clip_length(clipIndex); - QScopedPointer clip(m_playlist.get_clip(clipIndex)); - if (!clip) { - return false; - } - EffectManager effect(*clip.data()); - bool result = effect.editEffect(params, duration, replace); - return result; -} - -bool Track::editTrackEffect(const EffectsParameterList ¶ms, bool replace) -{ - EffectManager effect(m_playlist); - int duration = m_playlist.get_playtime() - 1; - return effect.editEffect(params, duration, replace); -} - -bool Track::removeEffect(double start, int effectIndex, bool updateIndex) -{ - int pos = frame(start); - int clipIndex = m_playlist.get_clip_index_at(pos); - QScopedPointer clip(m_playlist.get_clip(clipIndex)); - if (!clip) { - return false; - } - Mlt::Service clipService(clip->get_service()); - EffectManager effect(clipService); - return effect.removeEffect(effectIndex, updateIndex); -} - -bool Track::removeTrackEffect(int effectIndex, bool updateIndex) -{ - EffectManager effect(m_playlist); - return effect.removeEffect(effectIndex, updateIndex); -} - -bool Track::enableEffects(double start, const QList &effectIndexes, bool disable) -{ - int pos = frame(start); - int clipIndex = m_playlist.get_clip_index_at(pos); - QScopedPointer clip(m_playlist.get_clip(clipIndex)); - if (!clip) { - return false; - } - Mlt::Service clipService(clip->get_service()); - EffectManager effect(clipService); - return effect.enableEffects(effectIndexes, disable); -} - -bool Track::enableTrackEffects(const QList &effectIndexes, bool disable, bool remember) -{ - EffectManager effect(m_playlist); - return effect.enableEffects(effectIndexes, disable, remember); -} - -bool Track::moveEffect(double start, int oldPos, int newPos) -{ - int pos = frame(start); - int clipIndex = m_playlist.get_clip_index_at(pos); - QScopedPointer clip(m_playlist.get_clip(clipIndex)); - if (!clip) { - return false; - } - Mlt::Service clipService(clip->get_service()); - EffectManager effect(clipService); - return effect.moveEffect(oldPos, newPos); -} - -bool Track::moveTrackEffect(int oldPos, int newPos) -{ - EffectManager effect(m_playlist); - return effect.moveEffect(oldPos, newPos); -} - -QList Track::visibleClips() -{ - QList clips; - int tkState = state(); - if ((tkState & 1) != 0) { - // Video is hidden for this track, nothing visible - return clips; - } - QPoint current; - for (int i = 0; i < m_playlist.count(); i++) { - if (m_playlist.is_blank(i)) continue; - - // get producer, check if it has video - // TODO: playlist::clip_info(i, info) crashes on MLT < 6.6.0, so use variant until MLT 6.6.x is required - QScopedPointer info(m_playlist.clip_info(i)); - Mlt::Producer *clip = info->producer; - QString service = clip->get("mlt_service"); - if (service.contains(QStringLiteral("avformat"))) { - // Check if it is audio only - if (clip->get_int("video_index") == -1) { - continue; - } - } - // Found a clip - int cStart = info->start; - int length = info->frame_count; - if (current.isNull()) { - current.setX(cStart); - current.setY(cStart + length); - } else if (cStart - current.y() < 25) { - current.setY(cStart + length); - } else { - clips << current; - current.setX(cStart); - current.setY(cStart + length); - } - } - if (!current.isNull()) clips << current; - return clips; -} - -bool Track::resize_in_out(int pos, int in, int out) -{ - int ix = m_playlist.get_clip_index_at(pos); - m_playlist.resize_clip(ix, in, out); - return true; -} - -bool Track::hideClip(int pos, const QString &id, bool hide) -{ - int ix = m_playlist.get_clip_index_at(pos); - if (m_playlist.is_blank(ix)) { - return false; - } - QScopedPointer p(m_playlist.get_clip(ix)); - QString current = p->parent().get("id"); - if (current == id) { - if (!hide) { - m_playlist.parent().set("hide", m_playlist.parent().get_int("_autohide")); - m_playlist.parent().set("_autohide", (char *)nullptr); - return true; - } - int currentState = m_playlist.parent().get_int("hide"); - int newState; - switch (currentState) { - case 3: - case 1: - // Track is already blinded, nothing to do - return false; - case 2: - // Track is mutes, hide completely - newState = 3; - break; - default: - newState = 1; - break; - } - m_playlist.parent().set("hide", newState); - m_playlist.parent().set("_autohide", currentState); - return true; - } - return false; -} diff --git a/src/timeline/track.h b/src/timeline/track.h deleted file mode 100644 index 7f4e0ccf4..000000000 --- a/src/timeline/track.h +++ /dev/null @@ -1,237 +0,0 @@ -/* - * Kdenlive timeline track handling MLT playlist - * Copyright 2015 Kdenlive team - * Author: Vincent Pinon - * - * This program 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) version 3 or any later version - * accepted by the membership of KDE e.V. (or its successor approved - * by the membership of KDE e.V.), which shall act as a proxy - * defined in Section 14 of version 3 of the license. - * - * This program 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 this program. If not, see . - * - */ - -#ifndef TRACK_H -#define TRACK_H - -#include "definitions.h" -#include "mltcontroller/effectscontroller.h" -#include - -#include -#include - -class HeaderTrack; - -/** @brief Kdenlive timeline track, to access MLT playlist operations - * The track as seen in the video editor is actually a playlist - * in the MLT framework behind the scene. - * When one adds, deletes, moves and resizes clips on the track, - * it corresponds to playlist operations, simple or elaborate. - * The Track class handles the edit time to MLT frame & index - * correspondance, and builds complex operations on top of basic - * commands. - */ - -class Track : public QObject -{ - Q_OBJECT - -public: - /** @brief Track constructor - * @param playlist is the MLT object used for monitor/render - * @param fps is the read speed (frames per seconds) */ - explicit Track(int index, const QList &actions, Mlt::Playlist &playlist, TrackType trackType, int height, QWidget *parent = nullptr); - ~Track(); - - struct SlowmoInfo - { - double speed; - int strobe; - PlaylistState::ClipState state; - QString toString(const QLocale &locale) - { - QStringList str; - str << locale.toString(speed) << QString::number(strobe) << QString::number((int)state); - return str.join(QLatin1Char(':')); - } - void readFromString(const QString &str, const QLocale &locale) - { - speed = locale.toDouble(str.section(QLatin1Char(':'), 0, 0)); - strobe = str.section(QLatin1Char(':'), 1, 1).toInt(); - if (str.count(QLatin1Char(':')) == 1) { - state = PlaylistState::Original; - } else { - state = (PlaylistState::ClipState)str.section(QLatin1Char(':'), 2, 2).toInt(); - } - } - }; - - /// Property access function - Mlt::Playlist &playlist(); - qreal fps(); - /** List containing track effects */ - EffectsList effectsList; - /** Track type (audio / video) */ - TrackType type; - - /** @brief The track header widget */ - HeaderTrack *trackHeader; - - /** @brief convertion utility function - * @param time (in seconds) - * @return frame number */ - int frame(qreal t); - /** @brief get the playlist duration - * @return play time in seconds */ - qreal length(); - - /** @brief Returns MLT's track index */ - int index() const; - - /** @brief add a clip - * @param t is the time position to start the cut (in seconds) - * @param cut is a MLT Producer cut (resource + in/out timecodes) - * @param duplicate when true, we will create a copy of the clip if necessary - * @param mode allow insert in non-blanks by replacing (mode=1) or pushing (mode=2) content - * The playlist must be locked / unlocked before and after calling doAdd - * @return true if success */ - bool doAdd(qreal t, Mlt::Producer *cut, TimelineMode::EditMode mode); - bool add(qreal t, Mlt::Producer *parent, qreal tcut, qreal dtcut, PlaylistState::ClipState state, bool duplicate, TimelineMode::EditMode mode); - /** @brief Move a clip in the track - * @param start where clip is present (in seconds); - * @param end wher the clip should be moved - * @param mode allow insert in non-blanks by replacing (mode=1) or pushing (mode=2) content - * @return true if success */ - bool move(qreal start, qreal end, TimelineMode::EditMode mode = TimelineMode::NormalEdit); - /** @brief delete a clip - * @param time where clip is present (in seconds); - * @return true if success */ - bool del(qreal t, bool checkDuration = true); - /** delete a region - * @param t is the start, - * @param dt is the duration (in seconds) - * @return true if success */ - bool del(qreal t, qreal dt); - /** @brief change the clip length from start or end - * @param told is the current edge position, - * @param tnew is the target edge position (in seconds) - * @param end precises if we move the end of the left clip (\em true) - * or the start of the right clip (\em false) - * @return true if success */ - bool resize(qreal told, qreal tnew, bool end); - /** @brief split the clip at given position - * @param t is the cut time in playlist - * @return true if success */ - bool cut(qreal t); - /** @brief prepends a dash to the clip's id to prepare for replacement */ - void replaceId(const QString &id); - /** @brief replace all occurrences of a clip in the track with another resource - * @param id is the clip id - * @param original is the original replacement clip - * @param videoOnlyProducer is the video only (without sound) replacement clip - * @param newSlowMos the slowmotion producers required for replacement - * @return list of in/out that were replaced */ - QList replaceAll(const QString &id, Mlt::Producer *original, Mlt::Producer *videoOnlyProducer, const QMap &newSlowMos); - void updateEffects(const QString &id, Mlt::Producer *original); - /** @brief replace an instance of a clip with another resource - * @param t is the clip time in playlist - * @param prod is the replacement clip - * @return true if success */ - bool replace(qreal t, Mlt::Producer *prod, PlaylistState::ClipState state = PlaylistState::Original, - PlaylistState::ClipState originalState = PlaylistState::Original); - /** @brief look for a clip having a given property value - * @param name is the property name - * @param value is the searched value - * @param startindex is a playlist index to start the search from - * @return pointer to the first matching producer */ - // Mlt::Producer &find(const QByteArray &name, const QByteArray &value, int startindex = 0); - /** @brief get a producer clone for the track and pick an extract - * MLT (libav*) can't mix audio of a clip with itself, so we duplicate the producer for each track - * @param parent is the source media - * @param state is for Normal, Audio only or Video only - * @param forceCreation if true, we do not attempt to re-use existing track producer but recreate it - * @return producer cut for this track */ - Mlt::Producer *clipProducer(Mlt::Producer *parent, PlaylistState::ClipState state, bool forceCreation = false); - /** @brief Changes the speed of a clip in MLT's playlist. - * - * It creates a new "framebuffer" producer, which must have its "resource" - * property set to "video.mpg?0.6", where "video.mpg" is the path to the - * clip and "0.6" is the speed in percentage. The newly created producer - * will have its "id" property set to "slowmotion:parentid:speed", where - * "parentid" is the id of the original clip in the ClipManager list and - * "speed" is the current speed. - * If removeEffect is true, we revert to original avformat producer - */ - int changeClipSpeed(const ItemInfo &info, const ItemInfo &speedIndependantInfo, PlaylistState::ClipState state, double speed, int strobe, - Mlt::Producer *prod, const QString &id, Mlt::Properties passProps, bool removeEffect = false); - Mlt::Producer *buildSlowMoProducer(Mlt::Properties passProps, const QString &url, const QString &id, Track::SlowmoInfo info); - /** @brief Returns true if there is a clip with audio on this track */ - bool hasAudio(); - void setProperty(const QString &name, const QString &value); - void setProperty(const QString &name, int value); - const QString getProperty(const QString &name); - int getIntProperty(const QString &name); - TrackInfo info(); - void setInfo(const TrackInfo &info); - void lockTrack(bool locked); - int state(); - void setState(int state); - /** @brief Check if we have a blank space at pos and its length. - * Returns -1 if track is shorter, 0 if not blank and > 0 for blank length */ - int getBlankLength(int pos, bool fromBlankStart); - /** @brief Update producer properties on all instances of this clip. */ - void updateClipProperties(const QString &id, const QMap &properties); - /** @brief Returns a list of speed info for all slowmotion producer used on this track for an id. */ - QList getSlowmotionInfos(const QString &id); - /** @brief Returns the length of blank space from a position pos. */ - int spaceLength(int pos, bool fromBlankStart); - /** @brief Dis/enable all effects on this track. */ - void disableEffects(bool disable); - /** @brief Returns true if position is on last clip or beyond track length. */ - bool isLastClip(qreal t); - bool addEffect(double start, const EffectsParameterList ¶ms); - bool addTrackEffect(const EffectsParameterList ¶ms); - bool editEffect(double start, const EffectsParameterList ¶ms, bool replace); - bool editTrackEffect(const EffectsParameterList ¶ms, bool replace); - bool removeEffect(double start, int effectIndex, bool updateIndex); - bool removeTrackEffect(int effectIndex, bool updateIndex); - bool enableEffects(double start, const QList &effectIndexes, bool disable); - bool enableTrackEffects(const QList &effectIndexes, bool disable, bool remember = false); - bool moveEffect(double start, int oldPos, int newPos); - bool moveTrackEffect(int oldPos, int newPos); - QList visibleClips(); - bool resize_in_out(int pos, int in, int out); - /** @brief temporarily hide the track if it contains the clip id at position pos - * @returns true if the track was hidden - **/ - bool hideClip(int pos, const QString &id, bool hide); - -signals: - /** @brief notify track length change to update background - * @param duration is the new length */ - void newTrackDuration(int duration); - void storeSlowMotion(const QString &url, Mlt::Producer *prod); - -private: - /** Position in MLT's tractor */ - int m_index; - /** MLT playlist behind the scene */ - Mlt::Playlist m_playlist; - /** @brief Returns true is this MLT service needs duplication to work on multiple tracks */ - bool needsDuplicate(const QString &service) const; - void checkEffect(const QString effectName, int pos, int duration); - void checkEffects(const QStringList effectNames, int pos, int duration); -}; - -#endif // TRACK_H diff --git a/src/timeline/trackdialog.cpp b/src/timeline/trackdialog.cpp deleted file mode 100644 index 41329604b..000000000 --- a/src/timeline/trackdialog.cpp +++ /dev/null @@ -1,38 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "trackdialog.h" - -#include "kdenlivesettings.h" -#include "timeline.h" - -#include - -TrackDialog::TrackDialog(Timeline *timeline, QWidget *parent) - : QDialog(parent) -{ - // setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); - QIcon videoIcon = QIcon::fromTheme(QStringLiteral("kdenlive-show-video")); - QIcon audioIcon = QIcon::fromTheme(QStringLiteral("kdenlive-show-audio")); - setupUi(this); - for (int i = timeline->tracksCount() - 1; i > 0; i--) { - TrackInfo info = timeline->getTrackInfo(i); - comboTracks->addItem(info.type == VideoTrack ? videoIcon : audioIcon, info.trackName.isEmpty() ? QString::number(i) : info.trackName); - } -} diff --git a/src/timeline/trackdialog.h b/src/timeline/trackdialog.h deleted file mode 100644 index 5b9ae8ad0..000000000 --- a/src/timeline/trackdialog.h +++ /dev/null @@ -1,35 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TRACKDIALOG_H -#define TRACKDIALOG_H - -#include "ui_addtrack_ui.h" - -class Timeline; - -class TrackDialog : public QDialog, public Ui::AddTrack_UI -{ - Q_OBJECT - -public: - explicit TrackDialog(Timeline *timeline, QWidget *parent = nullptr); -}; - -#endif diff --git a/src/timeline/tracksconfigdialog.cpp b/src/timeline/tracksconfigdialog.cpp deleted file mode 100644 index 355b4679e..000000000 --- a/src/timeline/tracksconfigdialog.cpp +++ /dev/null @@ -1,213 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Till Theato (root@ttill.de) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "tracksconfigdialog.h" -#include "timeline/timeline.h" - -#include -#include -#include - -#include "klocalizedstring.h" - -TracksDelegate::TracksDelegate(QObject *parent) - : QItemDelegate(parent) -{ -} - -QWidget *TracksDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem & /* option */, const QModelIndex & /*index*/) const -{ - auto *comboBox = new KComboBox(parent); - comboBox->addItem(i18n("Video")); - comboBox->addItem(i18n("Audio")); - connect(comboBox, SIGNAL(activated(int)), this, SLOT(emitCommitData())); - return comboBox; -} - -void TracksDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const -{ - KComboBox *comboBox = qobject_cast(editor); - if (!comboBox) { - return; - } - const int pos = comboBox->findText(index.model()->data(index).toString(), Qt::MatchExactly); - comboBox->setCurrentIndex(pos); -} - -void TracksDelegate::setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const -{ - KComboBox *comboBox = qobject_cast(editor); - if (!comboBox) { - return; - } - model->setData(index, comboBox->currentText()); -} - -void TracksDelegate::emitCommitData() -{ - emit commitData(qobject_cast(sender())); -} - -TracksConfigDialog::TracksConfigDialog(Timeline *timeline, int selected, QWidget *parent) - : QDialog(parent) - , m_timeline(timeline) -{ - setupUi(this); - - table->setColumnCount(5); - table->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); - table->setHorizontalHeaderLabels(QStringList() << i18n("Name") << i18n("Type") << i18n("Hidden") << i18n("Muted") << i18n("Locked") << i18n("Composite")); - table->setSelectionMode(QAbstractItemView::SingleSelection); - table->setItemDelegateForColumn(1, new TracksDelegate(this)); - table->verticalHeader()->setHidden(true); - - buttonReset->setIcon(QIcon::fromTheme(QStringLiteral("document-revert"))); - buttonReset->setToolTip(i18n("Reset")); - connect(buttonReset, &QAbstractButton::clicked, this, &TracksConfigDialog::setupOriginal); - - buttonAdd->setIcon(QIcon::fromTheme(QStringLiteral("list-add"))); - buttonAdd->setToolTip(i18n("Add Track")); - buttonAdd->setEnabled(false); - - buttonDelete->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); - buttonDelete->setToolTip(i18n("Delete Track")); - connect(buttonDelete, &QAbstractButton::clicked, this, &TracksConfigDialog::slotDelete); - - buttonUp->setIcon(QIcon::fromTheme(QStringLiteral("arrow-up"))); - buttonUp->setToolTip(i18n("Move Track upwards")); - buttonUp->setEnabled(false); - - buttonDown->setIcon(QIcon::fromTheme(QStringLiteral("arrow-down"))); - buttonDown->setToolTip(i18n("Move Track downwards")); - buttonDown->setEnabled(false); - - setupOriginal(selected); - // table->resizeColumnToContents(0); - table->resizeColumnsToContents(); - /*QRect rect = table->geometry(); - rect.setWidth(table->horizontalHeader()->length()); - table->setGeometry(rect);*/ - table->horizontalHeader()->setStretchLastSection(true); - table->setMinimumSize(table->horizontalHeader()->length(), table->verticalHeader()->length() + table->horizontalHeader()->height() * 2); - connect(table, &QTableWidget::itemChanged, this, &TracksConfigDialog::slotUpdateRow); -} - -const QList TracksConfigDialog::tracksList() -{ - QList tracks; - TrackInfo info; - tracks.reserve(table->rowCount()); - for (int i = 0; i < table->rowCount(); i++) { - info.trackName = table->item(i, 0)->text(); - QTableWidgetItem *item = table->item(i, 1); - if (item->text() == i18n("Audio")) { - info.type = AudioTrack; - info.isBlind = true; - } else { - info.type = VideoTrack; - info.isBlind = (table->item(i, 2)->checkState() == Qt::Checked); - } - info.isMute = (table->item(i, 3)->checkState() == Qt::Checked); - info.isLocked = (table->item(i, 4)->checkState() == Qt::Checked); - tracks << info; - } - return tracks; -} - -QList TracksConfigDialog::deletedTracks() const -{ - return m_deletedRows; -} - -void TracksConfigDialog::setupOriginal(int selected) -{ - int max = m_timeline->visibleTracksCount(); - table->setRowCount(max); - - QStringList numbers; - TrackInfo info; - for (int i = 0; i < max; i++) { - numbers << QString::number(i); - info = m_timeline->getTrackInfo(max - i); - table->setItem(i, 0, new QTableWidgetItem(info.trackName)); - - QTableWidgetItem *item1 = new QTableWidgetItem(i18n("Video")); - if (info.type == AudioTrack) { - item1->setText(i18n("Audio")); - } - table->setItem(i, 1, item1); - table->openPersistentEditor(item1); - - QTableWidgetItem *item2 = new QTableWidgetItem(QString()); - item2->setFlags(item2->flags() & ~Qt::ItemIsEditable); - item2->setCheckState(info.isBlind ? Qt::Checked : Qt::Unchecked); - if (info.type == AudioTrack) { - item2->setFlags(item2->flags() & ~Qt::ItemIsEnabled); - } - table->setItem(i, 2, item2); - - QTableWidgetItem *item3 = new QTableWidgetItem(QString()); - item3->setFlags(item3->flags() & ~Qt::ItemIsEditable); - item3->setCheckState(info.isMute ? Qt::Checked : Qt::Unchecked); - table->setItem(i, 3, item3); - - QTableWidgetItem *item4 = new QTableWidgetItem(QString()); - item4->setFlags(item4->flags() & ~Qt::ItemIsEditable); - item4->setCheckState(info.isLocked ? Qt::Checked : Qt::Unchecked); - table->setItem(i, 4, item4); - } - table->setVerticalHeaderLabels(numbers); - - table->resizeColumnsToContents(); - if (selected != -1) { - table->selectRow(max - selected); - } - - m_deletedRows.clear(); -} - -void TracksConfigDialog::slotUpdateRow(QTableWidgetItem *item) -{ - if (table->column(item) == 1) { - QTableWidgetItem *item2 = table->item(table->row(item), 2); - if (item->text() == i18n("Audio")) { - item2->setFlags(item2->flags() & ~Qt::ItemIsEnabled); - item2->setCheckState(Qt::Checked); - } else { - item2->setFlags(item2->flags() | Qt::ItemIsEnabled); - item2->setCheckState(Qt::Unchecked); - } - } -} - -void TracksConfigDialog::slotDelete() -{ - int row = table->currentRow(); - int trackToDelete = table->rowCount() - row; - if (row < 0 || m_deletedRows.contains(trackToDelete)) { - return; - } - m_deletedRows.append(trackToDelete); - qSort(m_deletedRows); - for (int i = 0; i < table->columnCount(); ++i) { - QTableWidgetItem *item = table->item(row, i); - item->setFlags(Qt::NoItemFlags); - item->setBackground(palette().dark()); - } -} diff --git a/src/timeline/tracksconfigdialog.h b/src/timeline/tracksconfigdialog.h deleted file mode 100644 index 861cb0a67..000000000 --- a/src/timeline/tracksconfigdialog.h +++ /dev/null @@ -1,81 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2010 by Till Theato (root@ttill.de) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#ifndef TRACKSCONFIGDIALOG_H -#define TRACKSCONFIGDIALOG_H - -#include "ui_tracksconfigdialog_ui.h" - -#include - -class TracksDelegate : public QItemDelegate -{ - Q_OBJECT -public: - explicit TracksDelegate(QObject *parent = nullptr); - QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option, const QModelIndex &index) const override; - void setEditorData(QWidget *editor, const QModelIndex &index) const override; - void setModelData(QWidget *editor, QAbstractItemModel *model, const QModelIndex &index) const override; -private slots: - void emitCommitData(); -}; - -class TrackInfo; -class Timeline; -class QTableWidgetItem; - -/** - * @class TracksConfigDialog - * @brief A dialog to change the name, type, ... of tracks. - * @author Till Theato - */ - -class TracksConfigDialog : public QDialog, public Ui::TracksConfigDialog_UI -{ - Q_OBJECT -public: - /** @brief Sets up the table. - * @param doc the kdenlive document whose tracks to use - * @param selected the track which should be selected by default - * @param parent the parent widget */ - explicit TracksConfigDialog(Timeline *timeline, int selected = -1, QWidget *parent = nullptr); - - /** @brief Returns the new list of tracks created from the table. */ - const QList tracksList(); - - /** @brief A list of tracks, which sould be deleted. */ - QList deletedTracks() const; - -private slots: - /** @brief Updates the "hidden" checkbox if type was changed. */ - void slotUpdateRow(QTableWidgetItem *item); - -private slots: - /** @brief Recreates the table from the list of tracks in m_doc. */ - void setupOriginal(int selected = -1); - - /** @brief Marks a track to be deleted. */ - void slotDelete(); - -private: - Timeline *m_timeline; - QList m_deletedRows; -}; - -#endif diff --git a/src/timeline/transition.cpp b/src/timeline/transition.cpp deleted file mode 100644 index 948c0386b..000000000 --- a/src/timeline/transition.cpp +++ /dev/null @@ -1,573 +0,0 @@ -/*************************************************************************** - transition.cpp - description - ------------------- - begin : Tue Jan 24 2006 - copyright : (C) 2006 by Jean-Baptiste Mardelle - email : jb@ader.ch - ***************************************************************************/ - -/*************************************************************************** - * * - * This program 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. * - * * - ***************************************************************************/ - -#include "transition.h" -#include "clipitem.h" -#include "customtrackscene.h" -#include "customtrackview.h" - -#include "kdenlivesettings.h" -#include "mainwindow.h" - -#include "kdenlive_debug.h" - -#include -#include -#include -#include -#include -#include -#include - -Transition::Transition(const ItemInfo &info, int transitiontrack, double fps, const QDomElement ¶ms, bool automaticTransition) - : AbstractClipItem(info, QRectF(), fps) - , m_forceTransitionTrack(false) - , m_automaticTransition(automaticTransition) - , m_transitionTrack(transitiontrack) -{ - setZValue(4); - m_info.cropDuration = info.endPos - info.startPos; - if (QApplication::style()->styleHint(QStyle::SH_Widget_Animate, nullptr, QApplication::activeWindow()) != 0) { - // animation disabled - setRect(0, 0, m_info.cropDuration.frames(fps) - 0.02, (qreal)itemHeight()); - } else { - QPropertyAnimation *startAnimation = new QPropertyAnimation(this, "rect"); - startAnimation->setDuration(200); - const QRectF r(0, 0, m_info.cropDuration.frames(fps) - 0.02, (qreal)itemHeight() / 2); - const QRectF r2(0, 0, m_info.cropDuration.frames(fps) - 0.02, (qreal)itemHeight()); - startAnimation->setStartValue(r); - startAnimation->setEndValue(r2); - startAnimation->setEasingCurve(QEasingCurve::OutQuad); - startAnimation->start(QAbstractAnimation::DeleteWhenStopped); - } - - m_info.cropStart = GenTime(); - m_maxDuration = GenTime(600); - - if (m_automaticTransition) { - setBrush(QColor(200, 200, 50, 180)); - } else { - setBrush(QColor(200, 100, 50, 180)); - } - - if (params.isNull()) { - m_parameters = MainWindow::transitions.getEffectByTag(QStringLiteral("luma"), QStringLiteral("dissolve")).cloneNode().toElement(); - } else { - m_parameters = params; - } - if (m_automaticTransition) { - m_parameters.setAttribute(QStringLiteral("automatic"), 1); - } else if (m_parameters.attribute(QStringLiteral("automatic")) == QLatin1String("1")) { - m_automaticTransition = true; - } - if (m_parameters.attribute(QStringLiteral("force_track")) == QLatin1String("1")) { - m_forceTransitionTrack = true; - } - m_name = i18n(m_parameters.firstChildElement("name").text().toUtf8().data()); - - QDomNodeList namenode = m_parameters.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < namenode.count(); ++i) { - QDomElement pa = namenode.item(i).toElement(); - QString paramType = pa.attribute(QStringLiteral("type")); - if (paramType == QLatin1String("geometry") || paramType == QLatin1String("animated") || paramType == QLatin1String("animatedrect")) { - setAcceptDrops(true); - break; - } - } -} - -Transition::~Transition() -{ - blockSignals(true); - if (scene()) { - scene()->removeItem(this); - } -} - -Transition *Transition::clone(const ItemInfo &newInfo) -{ - const QDomElement xml = toXML().cloneNode().toElement(); - Transition *tr = new Transition(newInfo.isValid() ? newInfo : info(), transitionEndTrack(), m_fps, xml); - return tr; -} - -QString Transition::transitionTag() const -{ - return m_parameters.attribute(QStringLiteral("tag")); -} - -QStringList Transition::transitionInfo() const -{ - QStringList info; - info << m_name << m_parameters.attribute(QStringLiteral("tag")) << m_parameters.attribute(QStringLiteral("id")); - return info; -} - -bool Transition::isAutomatic() const -{ - return m_automaticTransition; -} - -void Transition::setAutomatic(bool automatic) -{ - m_automaticTransition = automatic; - if (automatic) { - m_parameters.setAttribute(QStringLiteral("automatic"), 1); - setBrush(QColor(200, 200, 50, 180)); - } else { - m_parameters.removeAttribute(QStringLiteral("automatic")); - setBrush(QColor(200, 100, 50, 180)); - } - update(); -} - -void Transition::setTransitionParameters(const QDomElement ¶ms) -{ - if (m_parameters != params) { - m_parameters = params; - if (m_parameters.attribute(QStringLiteral("force_track")) == QLatin1String("1")) { - setForcedTrack(true, m_parameters.attribute(QStringLiteral("transition_btrack")).toInt()); - } else if (m_parameters.attribute(QStringLiteral("force_track")) == QLatin1String("0")) { - setForcedTrack(false, m_parameters.attribute(QStringLiteral("transition_btrack")).toInt()); - } - m_name = i18n(m_parameters.firstChildElement("name").text().toUtf8().data()); - update(); - bool hasGeometry = false; - QDomNodeList namenode = m_parameters.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < namenode.count(); ++i) { - QDomElement pa = namenode.item(i).toElement(); - QString paramType = pa.attribute(QStringLiteral("type")); - if (paramType == QLatin1String("geometry") || paramType == QLatin1String("animated") || paramType == QLatin1String("animatedrect")) { - hasGeometry = true; - break; - } - } - setAcceptDrops(hasGeometry); - } -} - -int Transition::transitionEndTrack() const -{ - return m_transitionTrack; -} - -void Transition::updateTransitionEndTrack(int newtrack) -{ - if (!m_forceTransitionTrack) { - m_transitionTrack = newtrack; - } -} - -void Transition::setForcedTrack(bool force, int track) -{ - m_forceTransitionTrack = force; - m_transitionTrack = track; -} - -bool Transition::forcedTrack() const -{ - return m_forceTransitionTrack; -} - -void Transition::paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget * /*widget*/) -{ - const QRectF exposed = painter->worldTransform().mapRect(option->exposedRect); - const QRectF br = rect(); - QPen framePen; - framePen.setWidthF(1.2); - const QRectF mapped = painter->worldTransform().mapRect(br); - - QPointF p1(br.x(), br.y() + br.height() / 2 - 7); - painter->setWorldTransform(QTransform()); - QPainterPath p; - p.addRect(exposed); - - QPainterPath q; - if (KdenliveSettings::clipcornertype() == 0) { - q.addRoundedRect(mapped, 3, 3); - } else { - q.addRect(mapped); - } - painter->setClipPath(p.intersected(q)); - painter->fillRect(exposed, brush()); - const QString text = m_name + (m_forceTransitionTrack ? QStringLiteral("|>") : QString()); - - // Draw clip name - if (isSelected() || ((parentItem() != nullptr) && parentItem()->isSelected())) { - framePen.setColor(scene()->palette().highlight().color()); - framePen.setColor(Qt::red); - } else { - framePen.setColor(brush().color().darker()); - } - - const QRectF txtBounding = painter->boundingRect(mapped, Qt::AlignHCenter | Qt::AlignVCenter, QLatin1Char(' ') + text + QLatin1Char(' ')); - painter->setBrush(framePen.color()); - painter->setPen(framePen.color()); - painter->drawRoundedRect(txtBounding, 3, 3); - painter->setBrush(QBrush(Qt::NoBrush)); - - painter->setPen(Qt::white); - painter->drawText(txtBounding, Qt::AlignCenter, text); - - // Draw frame - if (KdenliveSettings::clipcornertype() == 1) { - framePen.setJoinStyle(Qt::MiterJoin); - } - painter->setPen(framePen); - painter->setClipping(false); - painter->setRenderHint(QPainter::Antialiasing, true); - if (KdenliveSettings::clipcornertype() == 0) { - painter->drawRoundedRect(mapped.adjusted(0, 0, -0.5, -0.5), 3, 3); - } else { - painter->drawRect(mapped.adjusted(0, 0, -0.5, -0.5)); - } -} - -int Transition::type() const -{ - return TransitionWidget; -} - -// virtual -QVariant Transition::itemChange(GraphicsItemChange change, const QVariant &value) -{ - if (change == QGraphicsItem::ItemSelectedChange) { - if (value.toBool()) { - setZValue(5); - } else { - setZValue(4); - } - } - CustomTrackScene *scene = nullptr; - if (change == ItemPositionChange) { - scene = projectScene(); - } - if (scene) { - // calculate new position. - if (scene->isZooming) { - // For some reason, mouse wheel on selected itm sometimes triggered - // a position change event corrupting timeline, so discard it - return pos(); - } - QPointF newPos = value.toPointF(); - int xpos = projectScene()->getSnapPointForPos((int)newPos.x(), KdenliveSettings::snaptopoints()); - xpos = qMax(xpos, 0); - newPos.setX(xpos); - int newTrack = trackForPos(newPos.y()); - QList lockedTracks = property("locked_tracks").value>(); - if (lockedTracks.contains(newTrack)) { - // Trying to move to a locked track - return pos(); - } - int maximumTrack = projectScene()->tracksCount(); - newTrack = qMin(newTrack, maximumTrack); - newTrack = qMax(newTrack, 0); - newPos.setY(posForTrack(newTrack) + itemOffset()); - - // Only one clip is moving - QRectF sceneShape = rect(); - sceneShape.translate(newPos); - QList items; - // TODO: manage transitions in OVERWRITE MODE - // if (projectScene()->editMode() == NORMALEDIT) - items = scene->items(sceneShape, Qt::IntersectsItemShape); - items.removeAll(this); - - bool forwardMove = newPos.x() > pos().x(); - if (!items.isEmpty()) { - for (int i = 0; i < items.count(); ++i) { - if (!items.at(i)->isEnabled()) { - continue; - } - if (items.at(i)->type() == type()) { - int offset = 0; - // Collision! - QPointF otherPos = items.at(i)->pos(); - if ((int)otherPos.y() != (int)pos().y()) { - return pos(); - } - if (forwardMove) { - offset = qMax(offset, (int)(newPos.x() - (static_cast(items.at(i))->startPos() - cropDuration()).frames(m_fps))); - } else { - offset = qMax(offset, (int)((static_cast(items.at(i))->endPos().frames(m_fps)) - newPos.x())); - } - - if (offset > 0) { - if (forwardMove) { - sceneShape.translate(QPointF(-offset, 0)); - newPos.setX(newPos.x() - offset); - } else { - sceneShape.translate(QPointF(offset, 0)); - newPos.setX(newPos.x() + offset); - } - QList subitems = scene->items(sceneShape, Qt::IntersectsItemShape); - subitems.removeAll(this); - for (int j = 0; j < subitems.count(); ++j) { - if (!subitems.at(j)->isEnabled()) { - continue; - } - if (subitems.at(j)->type() == type()) { - // move was not successful, revert to previous pos - m_info.startPos = GenTime((int)pos().x(), m_fps); - return pos(); - } - } - } - - m_info.track = newTrack; - m_info.startPos = GenTime((int)newPos.x(), m_fps); - - return newPos; - } - } - } - - m_info.track = newTrack; - m_info.startPos = GenTime((int)newPos.x(), m_fps); - ////qCDebug(KDENLIVE_LOG)<<"// ITEM NEW POS: "<scale().x(); - double maximumOffset = 6 / scale; - - QRectF rect = sceneBoundingRect(); - if (qAbs((int)(pos.x())) < maximumOffset) { - return ResizeStart; - } - if (qAbs((int)(pos.x() - (rect.width()))) < maximumOffset) { - return ResizeEnd; - } - return MoveOperation; -} - -// static -int Transition::itemHeight() -{ - return (int)(KdenliveSettings::trackheight() / 3 * 2 - 1); -} - -// static -int Transition::itemOffset() -{ - return (int)(KdenliveSettings::trackheight() / 3 * 2); -} - -QDomElement Transition::toXML() -{ - m_parameters.setAttribute(QStringLiteral("type"), transitionTag()); - // m_transitionParameters.setAttribute("inverted", invertTransition()); - m_parameters.setAttribute(QStringLiteral("transition_atrack"), track()); - m_parameters.setAttribute(QStringLiteral("transition_btrack"), m_transitionTrack); - m_parameters.setAttribute(QStringLiteral("start"), startPos().frames(m_fps)); - m_parameters.setAttribute(QStringLiteral("end"), endPos().frames(m_fps)); - m_parameters.setAttribute(QStringLiteral("force_track"), static_cast(m_forceTransitionTrack)); - m_parameters.setAttribute(QStringLiteral("automatic"), static_cast(m_automaticTransition)); - /*QDomNodeList namenode = m_parameters.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < namenode.count() ; ++i) { - QDomElement pa = namenode.item(i).toElement(); - if (pa.attribute(QStringLiteral("type")) == QLatin1String("simplekeyframe")) { - if (pa.attribute(QStringLiteral("keyframes")).isEmpty()) { - // Effect has a keyframe type parameter, we need to set the values - pa.setAttribute(QStringLiteral("keyframes"), QStringLiteral("0=") + pa.attribute(QStringLiteral("default"))); - } - } - }*/ - return m_parameters.cloneNode().toElement(); -} - -bool Transition::hasGeometry() -{ - QDomNodeList namenode = m_parameters.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < namenode.count(); ++i) { - QDomElement pa = namenode.item(i).toElement(); - QString paramType = pa.attribute(QStringLiteral("type")); - if (paramType == QLatin1String("geometry") || paramType == QLatin1String("animated") || paramType == QLatin1String("animatedrect")) { - return true; - } - } - return false; -} - -bool Transition::updateKeyframes(const ItemInfo &oldInfo, const ItemInfo &newInfo) -{ - QString keyframes; - QDomElement pa; - bool modified = false; - QDomNodeList namenode = m_parameters.elementsByTagName(QStringLiteral("parameter")); - for (int i = 0; i < namenode.count(); ++i) { - pa = namenode.item(i).toElement(); - QString type = pa.attribute(QStringLiteral("type")); - if (type == QLatin1String("geometry") || type == QLatin1String("animated") || type == QLatin1String("animatedrect")) { - keyframes = pa.attribute(QStringLiteral("value")); - break; - } - } - if (keyframes.isEmpty()) { - return false; - } - int duration = newInfo.cropDuration.frames(m_fps) - 1; - int oldEnd = oldInfo.cropDuration.frames(m_fps) - 1; - QStringList values = keyframes.split(QLatin1Char(';')); - int frame; - int i = 0; - if (oldEnd < duration) { - // Transition was expanded, check if we had a keyframe at end position - for (const QString &pos : values) { - if (!pos.contains(QLatin1Char('='))) { - ++i; - continue; - } - frame = pos.section(QLatin1Char('='), 0, 0).remove(QLatin1Char('~')).remove(QLatin1Char('|')).toInt(); - if (frame == oldEnd) { - // Move that keyframe to new end - QString separator = QStringLiteral("="); - if (pos.contains(QLatin1Char('~'))) { - separator.prepend(QLatin1Char('~')); - } else if (pos.contains(QLatin1Char('|'))) { - separator.prepend(QLatin1Char('|')); - } - values[i] = QString::number(duration) + separator + pos.section(QLatin1Char('='), 1); - pa.setAttribute(QStringLiteral("value"), values.join(QLatin1Char(';'))); - return true; - } - ++i; - } - return false; - } - if (oldEnd > duration) { - // Transition was shortened, check for out of bounds keyframes - for (const QString &pos : values) { - if (!pos.contains(QLatin1Char('='))) { - ++i; - continue; - } - frame = pos.section(QLatin1Char('='), 0, 0).remove(QLatin1Char('~')).remove(QLatin1Char('|')).toInt(); - if (frame > duration) { - modified = true; - break; - } - ++i; - } - } - if (modified) { - if (i > 0) { - // Check if there is a keyframe at transition end - QString prev = values.at(i - 1); - bool done = false; - if (prev.contains(QLatin1Char('='))) { - int previousKeyframe = prev.section(QLatin1Char('='), 0, 0).remove(QLatin1Char('~')).remove(QLatin1Char('|')).toInt(); - if (previousKeyframe == duration) { - // Remove the last keyframes - while (values.count() > i) { - values.removeLast(); - } - done = true; - } - } - if (!done) { - // Add new keyframe at end and remove last keyframes - QString last = values.at(i); - QString separator = QStringLiteral("="); - if (last.contains(QLatin1Char('~'))) { - separator.prepend(QLatin1Char('~')); - } else if (last.contains(QLatin1Char('|'))) { - separator.prepend(QLatin1Char('|')); - } - last = QString::number(duration) + separator + last.section(QLatin1Char('='), 1); - values[i] = last; - while (values.count() > (i + 1)) { - values.removeLast(); - } - } - } - pa.setAttribute(QStringLiteral("value"), values.join(QLatin1Char(';'))); - } - return true; -} - -void Transition::updateKeyframes(const QDomElement & /*effect*/) -{ -} - -// virtual -void Transition::dragEnterEvent(QGraphicsSceneDragDropEvent *event) -{ - if (isItemLocked()) { - event->setAccepted(false); - } else if (event->mimeData()->hasFormat(QStringLiteral("kdenlive/geometry"))) { - event->acceptProposedAction(); - m_selectionTimer.start(); - } else { - event->setAccepted(false); - } -} - -void Transition::dragLeaveEvent(QGraphicsSceneDragDropEvent *event) -{ - Q_UNUSED(event) - if (m_selectionTimer.isActive()) { - m_selectionTimer.stop(); - } -} - -void Transition::dragMoveEvent(QGraphicsSceneDragDropEvent *event) -{ - QGraphicsItem::dragMoveEvent(event); - if (m_selectionTimer.isActive() && !isSelected()) { - m_selectionTimer.start(); - } -} - -// virtual -void Transition::dropEvent(QGraphicsSceneDragDropEvent *event) -{ - if ((scene() != nullptr) && !scene()->views().isEmpty()) { - if (m_selectionTimer.isActive()) { - m_selectionTimer.stop(); - } - QString geometry = QString::fromUtf8(event->mimeData()->data(QStringLiteral("kdenlive/geometry"))); - event->acceptProposedAction(); - CustomTrackView *view = static_cast(scene()->views().constFirst()); - if (view) { - view->dropTransitionGeometry(this, geometry); - } - } -} - -bool Transition::checkKeyFrames(int width, int height, int previousDuration, int cutPos) -{ - // go through all effects this clip has - QDomDocument doc; - doc.appendChild(doc.importNode(m_parameters, true)); - bool clipEffectsModified = - resizeGeometries(m_parameters, width, height, previousDuration, cutPos == -1 ? 0 : cutPos, cropDuration().frames(m_fps) - 1, cropStart().frames(m_fps)); - QString newAnimation = - resizeAnimations(m_parameters, previousDuration, cutPos == -1 ? 0 : cutPos, cropDuration().frames(m_fps) - 1, cropStart().frames(m_fps)); - if (!newAnimation.isEmpty()) { - clipEffectsModified = true; - } - return clipEffectsModified; -} diff --git a/src/timeline/transition.h b/src/timeline/transition.h deleted file mode 100644 index 9300c8ba0..000000000 --- a/src/timeline/transition.h +++ /dev/null @@ -1,98 +0,0 @@ -/*************************************************************************** - transition.h - description - ------------------- - begin : Tue Jan 24 2006 - copyright : (C) 2006 by Jean-Baptiste Mardelle - email : jb@ader.ch - ***************************************************************************/ - -/*************************************************************************** - * * - * This program 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. * - * * - ***************************************************************************/ - -/** - * @class Transition - * @author Jean-Baptiste Mardelle - * @brief Describes a transition with a name, parameters, keyframes, etc. - */ - -#ifndef TRANSITION_H -#define TRANSITION_H - -#include "abstractclipitem.h" -#include "definitions.h" -#include "gentime.h" - -#include -#include -#include -#include - -class ClipItem; - -class Transition : public AbstractClipItem -{ - Q_OBJECT -public: - Transition(const ItemInfo &info, int transitiontrack, double fps, const QDomElement ¶ms = QDomElement(), bool automaticTransition = false); - virtual ~Transition(); - void paint(QPainter *painter, const QStyleOptionGraphicsItem *option, QWidget *widget) override; - int type() const override; - - /** @brief Returns an XML representation of this transition. */ - QDomElement toXML(); - - /** @brief Returns the track number of the transition in the playlist. */ - int transitionEndTrack() const; - QString transitionTag() const; - QStringList transitionInfo() const; - OperationType operationMode(const QPointF &pos, Qt::KeyboardModifiers modifiers) override; - void updateKeyframes(const QDomElement &effect) override; - static int itemHeight(); - static int itemOffset(); - // const QMap< QString, QString > transitionParameters() const; - void setTransitionParameters(const QDomElement ¶ms); - void setTransitionTrack(int track); - - /** @brief Links the transition to another track. - * - * This happens only if the current track is not forced. */ - void updateTransitionEndTrack(int newtrack); - void setForcedTrack(bool force, int track); - bool forcedTrack() const; - Transition *clone(const ItemInfo &newInfo = ItemInfo()); - bool isAutomatic() const; - void setAutomatic(bool automatic); - bool hasGeometry(); - /** @brief When a transition is resized, check if keyframes are out of the transition and fix if necessary. - * @param oldEnd the previous transition end, so that when we expand the transition, if there is a keyframe at end we move it - */ - bool updateKeyframes(const ItemInfo &oldInfo, const ItemInfo &newInfo); - bool checkKeyFrames(int width, int height, int previousDuration, int cutPos = -1); - -protected: - QVariant itemChange(GraphicsItemChange change, const QVariant &value) override; - void dragEnterEvent(QGraphicsSceneDragDropEvent *event) override; - void dragLeaveEvent(QGraphicsSceneDragDropEvent *event) override; - void dragMoveEvent(QGraphicsSceneDragDropEvent *event) override; - void dropEvent(QGraphicsSceneDragDropEvent *event) override; - -private: - QString m_name; - bool m_forceTransitionTrack; - - /** @brief True if the transition is attached to its clip. */ - bool m_automaticTransition; - - /** @brief Contains the transition parameters. */ - QDomElement m_parameters; - - int m_transitionTrack; -}; - -#endif diff --git a/src/timeline/transitionhandler.cpp b/src/timeline/transitionhandler.cpp deleted file mode 100644 index 8a9ec62a2..000000000 --- a/src/timeline/transitionhandler.cpp +++ /dev/null @@ -1,702 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2015 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -#include "transitionhandler.h" -#include "kdenlivesettings.h" -#include "mainwindow.h" -#include "mltcontroller/effectscontroller.h" - -TransitionHandler::TransitionHandler(Mlt::Tractor *tractor) - : QObject() - , m_tractor(tractor) -{ -} - -bool TransitionHandler::addTransition(const QString &tag, int a_track, int b_track, GenTime in, GenTime out, const QDomElement &xml) -{ - if (in >= out) { - return false; - } - double fps = m_tractor->get_fps(); - QMap args = getTransitionParamsFromXml(xml); - QScopedPointer field(m_tractor->field()); - - Mlt::Transition transition(*m_tractor->profile(), tag.toUtf8().constData()); - if (!transition.is_valid()) { - return false; - } - if (out != GenTime()) { - transition.set_in_and_out((int)in.frames(fps), (int)out.frames(fps) - 1); - } - - QMap::Iterator it; - QString key; - if (xml.attribute(QStringLiteral("automatic")) == QLatin1String("1")) { - transition.set("automatic", 1); - } - ////qCDebug(KDENLIVE_LOG) << " ------ ADDING TRANSITION PARAMs: " << args.count(); - if (xml.hasAttribute(QStringLiteral("id"))) { - transition.set("kdenlive_id", xml.attribute(QStringLiteral("id")).toUtf8().constData()); - } - if (xml.hasAttribute(QStringLiteral("force_track"))) { - transition.set("force_track", xml.attribute(QStringLiteral("force_track")).toInt()); - } - - for (it = args.begin(); it != args.end(); ++it) { - key = it.key(); - if (!it.value().isEmpty()) { - transition.set(key.toUtf8().constData(), it.value().toUtf8().constData()); - } - ////qCDebug(KDENLIVE_LOG) << " ------ ADDING TRANS PARAM: " << key << ": " << it.value(); - } - // attach transition - m_tractor->lock(); - plantTransition(field.data(), transition, a_track, b_track); - // field->plant_transition(*transition, a_track, b_track); - m_tractor->unlock(); - return true; -} - -void TransitionHandler::initTransition(const QDomElement &xml) -{ - QMap params = getTransitionParamsFromXml(xml); - QMapIterator i(params); - while (i.hasNext()) { - i.next(); - EffectsList::setParameter(xml, i.key(), i.value()); - } -} - -QMap TransitionHandler::getTransitionParamsFromXml(const QDomElement &xml) -{ - QDomNodeList attribs = xml.elementsByTagName(QStringLiteral("parameter")); - QMap map; - QLocale locale; - for (int i = 0; i < attribs.count(); ++i) { - QDomElement e = attribs.item(i).toElement(); - QString name = e.attribute(QStringLiteral("name")); - if (e.hasAttribute(QStringLiteral("value"))) { - map[name] = e.attribute(QStringLiteral("value")); - } else { - QString defaultValue = e.attribute(QStringLiteral("default")); - // special case: luma file, we need to find full path for the default luma - if (!defaultValue.isEmpty() && e.attribute(QStringLiteral("paramlist")) == QLatin1String("%lumaPaths")) { - QString lumaFolder; - if (m_tractor->profile()->width() > 1000) { - lumaFolder = QStringLiteral("HD"); - } else { - lumaFolder = QStringLiteral("PAL"); - } - QStringList lumas = MainWindow::m_lumaFiles.value(lumaFolder); - bool found = false; - for (const QString &luma : lumas) { - if (QUrl::fromLocalFile(luma).fileName() == defaultValue) { - map[name] = luma; - found = true; - break; - } - } - if (!found) { - if (lumas.isEmpty()) { - // Something is wrong - map[name] = QString(); - } else { - map[name] = lumas.constFirst(); - } - } - } else { - if (defaultValue.contains(QLatin1Char('%'))) { - defaultValue = EffectsController::getStringRectEval(defaultValue); - } - map[name] = defaultValue; - } - } - double factor = e.attribute(QStringLiteral("factor"), QStringLiteral("1")).toDouble(); - double offset = e.attribute(QStringLiteral("offset"), QStringLiteral("0")).toDouble(); - if (factor != 1 || offset != 0) { - if (e.attribute(QStringLiteral("type")) == QLatin1String("simplekeyframe")) { - QStringList values = map.value(name).split(QLatin1Char(';'), QString::SkipEmptyParts); - for (int j = 0; j < values.count(); ++j) { - QString pos = values.at(j).section(QLatin1Char('='), 0, 0); - double val = (values.at(j).section(QLatin1Char('='), 1, 1).toDouble() - offset) / factor; - values[j] = pos + QLatin1Char('=') + locale.toString(val); - } - map[name] = values.join(QLatin1Char(';')); - } else if (e.attribute(QStringLiteral("type")) != QLatin1String("addedgeometry")) { - map[name] = locale.toString((locale.toDouble(map.value(name)) - offset) / factor); - // map[name]=map[name].replace(".",","); //FIXME how to solve locale conversion of . , - } - } - if (e.attribute(QStringLiteral("namedesc")).contains(QLatin1Char(';'))) { - // TODO: Deprecated, does not seem used anywhere... - QString format = e.attribute(QStringLiteral("format")); - QStringList separators = format.split(QStringLiteral("%d"), QString::SkipEmptyParts); - QStringList values = map.value(name).split(QRegExp(QStringLiteral("[,:;x]"))); - QString neu; - QTextStream txtNeu(&neu); - if (!values.isEmpty()) { - txtNeu << (int)values[0].toDouble(); - } - int j = 0; - for (j = 0; j < separators.size() && j + 1 < values.size(); ++j) { - txtNeu << separators[j]; - txtNeu << (int)(values[j + 1].toDouble()); - } - if (j < separators.size()) { - txtNeu << separators[j]; - } - map[name] = neu; - } - } - return map; -} - -// adds the transition by keeping the instance order from topmost track down to background -void TransitionHandler::plantTransition(Mlt::Transition &tr, int a_track, int b_track) -{ - QScopedPointer field(m_tractor->field()); - plantTransition(field.data(), tr, a_track, b_track); -} - -// adds the transition by keeping the instance order from topmost track down to background -void TransitionHandler::plantTransition(Mlt::Field *field, Mlt::Transition &tr, int a_track, int b_track) -{ - mlt_service nextservice = mlt_service_get_producer(field->get_service()); - mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice); - QString resource = mlt_properties_get(properties, "mlt_service"); - QList trList; - mlt_properties insertproperties = tr.get_properties(); - QString insertresource = mlt_properties_get(insertproperties, "mlt_service"); - bool isMixTransition = insertresource == QLatin1String("mix"); - - mlt_service_type mlt_type = mlt_service_identify(nextservice); - while (mlt_type == transition_type) { - Mlt::Transition transition((mlt_transition)nextservice); - nextservice = mlt_service_producer(nextservice); - int aTrack = transition.get_a_track(); - int bTrack = transition.get_b_track(); - int internal = transition.get_int("internal_added"); - if ((isMixTransition || resource != QLatin1String("mix")) && (internal > 0 || aTrack < a_track || (aTrack == a_track && bTrack > b_track))) { - Mlt::Properties trans_props(transition.get_properties()); - auto *cp = new Mlt::Transition(*m_tractor->profile(), transition.get("mlt_service")); - Mlt::Properties new_trans_props(cp->get_properties()); - // new_trans_props.inherit(trans_props); - cloneProperties(new_trans_props, trans_props); - trList.append(cp); - field->disconnect_service(transition); - } - // else qCDebug(KDENLIVE_LOG) << "// FOUND TRANS OK, "<plant_transition(tr, a_track, b_track); - - // re-add upper transitions - for (int i = trList.count() - 1; i >= 0; --i) { - ////qCDebug(KDENLIVE_LOG)<< "REPLANT ON TK: "<get_a_track()<<", "<get_b_track(); - field->plant_transition(*trList.at(i), trList.at(i)->get_a_track(), trList.at(i)->get_b_track()); - } - qDeleteAll(trList); -} - -void TransitionHandler::cloneProperties(Mlt::Properties &dest, Mlt::Properties &source) -{ - int count = source.count(); - int i = 0; - for (i = 0; i < count; i++) { - char *value = source.get(i); - if (value != nullptr) { - char *name = source.get_name(i); - if (name != nullptr && name[0] != QLatin1Char('_')) { - dest.set(name, value); - } - } - } -} - -void TransitionHandler::updateTransition(const QString &oldTag, const QString &tag, int a_track, int b_track, GenTime in, GenTime out, const QDomElement &xml, - bool force) -{ - if (oldTag == tag && !force) { - updateTransitionParams(tag, a_track, b_track, in, out, xml); - } else { - ////qCDebug(KDENLIVE_LOG)<<"// DELETING TRANS: "< field(m_tractor->field()); - field->lock(); - double fps = m_tractor->get_fps(); - mlt_service nextservice = mlt_service_get_producer(field->get_service()); - mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice); - QString resource = mlt_properties_get(properties, "mlt_service"); - int in_pos = (int)in.frames(fps); - int out_pos = (int)out.frames(fps) - 1; - - mlt_service_type mlt_type = mlt_service_identify(nextservice); - while (mlt_type == transition_type) { - mlt_transition tr = (mlt_transition)nextservice; - int currentTrack = mlt_transition_get_b_track(tr); - int currentBTrack = mlt_transition_get_a_track(tr); - int currentIn = (int)mlt_transition_get_in(tr); - int currentOut = (int)mlt_transition_get_out(tr); - - // //qCDebug(KDENLIVE_LOG)<<"Looking for transition : " << currentIn <<'x'< map = getTransitionParamsFromXml(xml); - QMap::Iterator it; - QString key; - mlt_properties transproperties = MLT_TRANSITION_PROPERTIES(tr); - - QString currentId = mlt_properties_get(transproperties, "kdenlive_id"); - if (currentId != xml.attribute(QStringLiteral("id"))) { - // The transition ID is not the same, so reset all properties - mlt_properties_set(transproperties, "kdenlive_id", xml.attribute(QStringLiteral("id")).toUtf8().constData()); - // Cleanup previous properties - QStringList permanentProps; - permanentProps << QStringLiteral("factory") << QStringLiteral("kdenlive_id") << QStringLiteral("mlt_service") << QStringLiteral("mlt_type") - << QStringLiteral("in"); - permanentProps << QStringLiteral("out") << QStringLiteral("a_track") << QStringLiteral("b_track"); - for (int i = 0; i < mlt_properties_count(transproperties); ++i) { - QString propName = mlt_properties_get_name(transproperties, i); - if (!propName.startsWith('_') && !permanentProps.contains(propName)) { - mlt_properties_set(transproperties, propName.toUtf8().constData(), ""); - } - } - } - - mlt_properties_set_int(transproperties, "force_track", xml.attribute(QStringLiteral("force_track")).toInt()); - mlt_properties_set_int(transproperties, "automatic", xml.attribute(QStringLiteral("automatic"), QStringLiteral("0")).toInt()); - - if (currentBTrack != a_track) { - mlt_properties_set_int(transproperties, "a_track", a_track); - } - for (it = map.begin(); it != map.end(); ++it) { - key = it.key(); - mlt_properties_set(transproperties, key.toUtf8().constData(), it.value().toUtf8().constData()); - // qCDebug(KDENLIVE_LOG) << " ------ UPDATING TRANS PARAM: " << key.toUtf8().constData() << ": " << it.value().toUtf8().constData(); - // filter->set("kdenlive_id", id); - } - break; - } - nextservice = mlt_service_producer(nextservice); - if (nextservice == nullptr) { - break; - } - properties = MLT_SERVICE_PROPERTIES(nextservice); - mlt_type = mlt_service_identify(nextservice); - resource = mlt_properties_get(properties, "mlt_service"); - } - field->unlock(); - // askForRefresh(); - // if (m_isBlocked == 0) m_mltConsumer->set("refresh", 1); -} - -bool TransitionHandler::deleteTransition(const QString &tag, int /*a_track*/, int b_track, GenTime in, GenTime out, const QDomElement & /*xml*/, - bool /*do_refresh*/) -{ - QScopedPointer field(m_tractor->field()); - field->lock(); - mlt_service nextservice = mlt_service_get_producer(field->get_service()); - mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice); - QString resource = mlt_properties_get(properties, "mlt_service"); - double fps = m_tractor->get_fps(); - const int old_pos = (int)((in + out).frames(fps) / 2); - bool found = false; - ////qCDebug(KDENLIVE_LOG) << " del trans pos: " << in.frames(25) << '-' << out.frames(25); - - mlt_service_type mlt_type = mlt_service_identify(nextservice); - while (mlt_type == transition_type) { - mlt_transition tr = (mlt_transition)nextservice; - int currentTrack = mlt_transition_get_b_track(tr); - int currentIn = (int)mlt_transition_get_in(tr); - int currentOut = (int)mlt_transition_get_out(tr); - ////qCDebug(KDENLIVE_LOG) << "// FOUND EXISTING TRANS, IN: " << currentIn << ", OUT: " << currentOut << ", TRACK: " << currentTrack; - - if (resource == tag && b_track == currentTrack && currentIn <= old_pos && currentOut >= old_pos) { - found = true; - mlt_field_disconnect_service(field->get_field(), nextservice); - break; - } - nextservice = mlt_service_producer(nextservice); - if (nextservice == nullptr) { - break; - } - properties = MLT_SERVICE_PROPERTIES(nextservice); - mlt_type = mlt_service_identify(nextservice); - resource = mlt_properties_get(properties, "mlt_service"); - } - field->unlock(); - // askForRefresh(); - // if (m_isBlocked == 0) m_mltConsumer->set("refresh", 1); - return found; -} - -void TransitionHandler::deleteTrackTransitions(int ix) -{ - QScopedPointer field(m_tractor->field()); - mlt_service nextservice = mlt_service_get_producer(field->get_service()); - mlt_service_type type = mlt_service_identify(nextservice); - while (type == transition_type) { - Mlt::Transition transition((mlt_transition)nextservice); - nextservice = mlt_service_producer(nextservice); - int currentTrack = transition.get_b_track(); - if (ix == currentTrack) { - field->disconnect_service(transition); - } - if (nextservice == nullptr) { - break; - } - type = mlt_service_identify(nextservice); - } -} - -bool TransitionHandler::moveTransition(const QString &type, int startTrack, int newTrack, int newTransitionTrack, GenTime oldIn, GenTime oldOut, GenTime newIn, - GenTime newOut) -{ - double fps = m_tractor->get_fps(); - int new_in = (int)newIn.frames(fps); - int new_out = (int)newOut.frames(fps) - 1; - if (new_in >= new_out) { - return false; - } - int old_in = (int)oldIn.frames(fps); - int old_out = (int)oldOut.frames(fps) - 1; - - QScopedPointer field(m_tractor->field()); - field->lock(); - mlt_service nextservice = mlt_service_get_producer(field->get_service()); - mlt_properties properties = MLT_SERVICE_PROPERTIES(nextservice); - QString resource = mlt_properties_get(properties, "mlt_service"); - int old_pos = (int)(old_in + old_out) / 2; - bool found = false; - mlt_service_type mlt_type = mlt_service_identify(nextservice); - while (mlt_type == transition_type) { - Mlt::Transition transition((mlt_transition)nextservice); - nextservice = mlt_service_producer(nextservice); - int currentTrack = transition.get_b_track(); - int currentIn = (int)transition.get_in(); - int currentOut = (int)transition.get_out(); - - if (resource == type && startTrack == currentTrack && currentIn <= old_pos && currentOut >= old_pos) { - found = true; - if (newTrack - startTrack != 0) { - Mlt::Properties trans_props(transition.get_properties()); - Mlt::Transition new_transition(*m_tractor->profile(), transition.get("mlt_service")); - Mlt::Properties new_trans_props(new_transition.get_properties()); - // We cannot use MLT's property inherit because it also clones internal values like _unique_id which messes up the playlist - cloneProperties(new_trans_props, trans_props); - new_transition.set_in_and_out(new_in, new_out); - field->disconnect_service(transition); - plantTransition(field.data(), new_transition, newTransitionTrack, newTrack); - } else { - transition.set_in_and_out(new_in, new_out); - } - break; - } - if (nextservice == nullptr) { - break; - } - properties = MLT_SERVICE_PROPERTIES(nextservice); - mlt_type = mlt_service_identify(nextservice); - resource = mlt_properties_get(properties, "mlt_service"); - } - field->unlock(); - // if (m_isBlocked == 0) m_mltConsumer->set("refresh", 1); - return found; -} - -Mlt::Transition *TransitionHandler::getTransition(const QString &name, int b_track, int a_track, bool internalTransition) const -{ - QScopedPointer service(m_tractor->field()); - while ((service != nullptr) && service->is_valid()) { - if (service->type() == transition_type) { - Mlt::Transition t((mlt_transition)service->get_service()); - if (name == t.get("mlt_service") && t.get_b_track() == b_track) { - if (a_track == -1 || t.get_a_track() == a_track) { - int internal = t.get_int("internal_added"); - if (internal == 0) { - if (!internalTransition) { - return new Mlt::Transition(t); - } - } else if (internalTransition) { - return new Mlt::Transition(t); - } - } - } - } - service.reset(service->producer()); - } - return nullptr; -} - -Mlt::Transition *TransitionHandler::getTrackTransition(const QStringList &names, int b_track, int a_track) const -{ - QScopedPointer service(m_tractor->field()); - while ((service != nullptr) && service->is_valid()) { - if (service->type() == transition_type) { - Mlt::Transition t((mlt_transition)service->get_service()); - int internal = t.get_int("internal_added"); - if (internal >= 200) { - if (names.contains(t.get("mlt_service")) && t.get_b_track() == b_track && (a_track == -1 || t.get_a_track() == a_track)) { - return new Mlt::Transition(t); - } - } - } - service.reset(service->producer()); - } - return nullptr; -} - -void TransitionHandler::duplicateTransitionOnPlaylist(int in, int out, const QString &tag, const QDomElement &xml, int a_track, int b_track, Mlt::Field *field) -{ - QMap args = getTransitionParamsFromXml(xml); - Mlt::Transition transition(*m_tractor->profile(), tag.toUtf8().constData()); - if (!transition.is_valid()) { - return; - } - if (out != 0) { - transition.set_in_and_out(in, out); - } - - QMap::Iterator it; - QString key; - if (xml.attribute(QStringLiteral("automatic")) == QLatin1String("1")) { - transition.set("automatic", 1); - } - ////qCDebug(KDENLIVE_LOG) << " ------ ADDING TRANSITION PARAMs: " << args.count(); - if (xml.hasAttribute(QStringLiteral("id"))) { - transition.set("kdenlive_id", xml.attribute(QStringLiteral("id")).toUtf8().constData()); - } - if (xml.hasAttribute(QStringLiteral("force_track"))) { - transition.set("force_track", xml.attribute(QStringLiteral("force_track")).toInt()); - } - - for (it = args.begin(); it != args.end(); ++it) { - key = it.key(); - if (!it.value().isEmpty()) { - transition.set(key.toUtf8().constData(), it.value().toUtf8().constData()); - } - ////qCDebug(KDENLIVE_LOG) << " ------ ADDING TRANS PARAM: " << key << ": " << it.value(); - } - // attach transition - field->plant_transition(transition, a_track, b_track); -} - -void TransitionHandler::enableMultiTrack(bool enable) -{ - int tracks = m_tractor->count(); - if (tracks < 3) { - // we need at leas 3 tracks (black bg track + 2 tracks to use this) - return; - } - QStringList compositeService{QStringLiteral("qtblend"), QStringLiteral("frei0r.cairoblend"), QStringLiteral("movit.overlay")}; - QScopedPointer service(m_tractor->field()); - QScopedPointer field(m_tractor->field()); - field->lock(); - if (enable) { - // disable track composition (frei0r.cairoblend) - mlt_service nextservice = mlt_service_get_producer(field->get_service()); - mlt_service_type type = mlt_service_identify(nextservice); - while (type == transition_type) { - Mlt::Transition transition((mlt_transition)nextservice); - nextservice = mlt_service_producer(nextservice); - int added = transition.get_int("internal_added"); - if (added == 237) { - if (compositeService.contains(transition.get("mlt_service")) && transition.get_int("disable") == 0) { - transition.set("disable", 1); - transition.set("split_disable", 1); - } - } - if (nextservice == nullptr) { - break; - } - type = mlt_service_identify(nextservice); - } - // Search for visible tracks and arrange them on a 2x2 grid. - // If there are more than 4 visible tracks, the extra - // tracks will be displayed without rescaling on top of the grid. - // The user has to manually hide them. - for (int i = 1, screen = 0; i < tracks && screen < 4; ++i) { - Mlt::Producer trackProducer(m_tractor->track(i)); - // A track is in hidden state in "hide" has the bit 0x01 set. - // See Track::setInfo (in track.cpp) for details - const int trackVisibilityFlags = QString(trackProducer.get("hide")).toInt(); - const bool trackVisible = ( (trackVisibilityFlags & 1) == 0 ); - if (trackVisible) { - Mlt::Transition transition(*m_tractor->profile(), "composite"); - transition.set("mlt_service", "composite"); - transition.set("a_track", 0); - transition.set("b_track", i); - transition.set("distort", 0); - transition.set("aligned", 0); - // 200 is an arbitrary number so we can easily remove these transition later - transition.set("internal_added", 200); - QString geometry; - switch (screen) { - case 0: - geometry = QStringLiteral("0/0:50%x50%"); - break; - case 1: - geometry = QStringLiteral("50%/0:50%x50%"); - break; - case 2: - geometry = QStringLiteral("0/50%:50%x50%"); - break; - case 3: - default: - geometry = QStringLiteral("50%/50%:50%x50%"); - break; - } - transition.set("geometry", geometry.toUtf8().constData()); - transition.set("always_active", 1); - field->plant_transition(transition, 0, i); - screen++; - } - } - } else { - mlt_service nextservice = mlt_service_get_producer(field->get_service()); - mlt_service_type type = mlt_service_identify(nextservice); - while (type == transition_type) { - Mlt::Transition transition((mlt_transition)nextservice); - nextservice = mlt_service_producer(nextservice); - int added = transition.get_int("internal_added"); - if (added == 200) { - field->disconnect_service(transition); - } else if (added == 237) { - // re-enable track compositing - if (compositeService.contains(transition.get("mlt_service")) && transition.get_int("split_disable") == 1) { - transition.set("disable", 0); - transition.set("split_disable", (char *)nullptr); - } - } - if (nextservice == nullptr) { - break; - } - type = mlt_service_identify(nextservice); - } - } - field->unlock(); - emit refresh(); -} - -// static -const QString TransitionHandler::compositeTransition() -{ - if (KdenliveSettings::gpu_accel()) { - return QStringLiteral("movit.overlay"); - } - if (MainWindow::transitions.hasTransition(QStringLiteral("qtblend"))) { - return QStringLiteral("qtblend"); - } - if (MainWindow::transitions.hasTransition(QStringLiteral("frei0r.cairoblend"))) { - return QStringLiteral("frei0r.cairoblend"); - } - return QStringLiteral("composite"); -} - -void TransitionHandler::rebuildTransitions(int mode, const QList &videoTracks, int maxTrack) -{ - QStringList compositeService{QStringLiteral("qtblend"), QStringLiteral("composite"), QStringLiteral("frei0r.cairoblend"), QStringLiteral("movit.overlay")}; - QList disabled; - QScopedPointer service(m_tractor->field()); - Mlt::Field *field = m_tractor->field(); - field->lock(); - // Get the list of composite transitions - while ((service != nullptr) && service->is_valid()) { - if (service->type() == transition_type) { - Mlt::Transition t((mlt_transition)service->get_service()); - int internal = t.get_int("internal_added"); - if (internal == 237) { - QString serviceName = t.get("mlt_service"); - if (serviceName == QLatin1String("mix")) { - field->disconnect_service(t); - } else if (compositeService.contains(serviceName)) { - if (mode < 0) { - mode = serviceName == QLatin1String("composite") ? 1 : 2; - } - field->disconnect_service(t); - } - } - } - service.reset(service->producer()); - } - // Rebuild audio mix - for (int i = 1; i < maxTrack; i++) { - Mlt::Transition transition(*m_tractor->profile(), "mix"); - transition.set("always_active", 1); - if (sumAudioMixAvailable()) { - transition.set("sum", 1); - } else { - transition.set("combine", 1); - } - transition.set("a_track", 0); - transition.set("b_track", i); - transition.set("internal_added", 237); - field->plant_transition(transition, 0, i); - } - - if (mode <= 0) { - // no compositing wanted, return - field->unlock(); - delete field; - return; - } - // Re-add correct composite transitions - QString composite; - QString compositeGeometry; - if (mode == 1) { - composite = QStringLiteral("composite"); - compositeGeometry = QStringLiteral("0=0/0:%1x%2").arg(m_tractor->profile()->width()).arg(m_tractor->profile()->height()); - } else { - composite = compositeTransition(); - } - for (int track : videoTracks) { - Mlt::Transition transition(*m_tractor->profile(), composite.toUtf8().constData()); - transition.set("always_active", 1); - transition.set("a_track", 0); - transition.set("b_track", track); - if (mode == 1) { - transition.set("valign", "middle"); - transition.set("halign", "centre"); - transition.set("fill", 1); - transition.set("geometry", compositeGeometry.toUtf8().constData()); - } - transition.set("internal_added", 237); - field->plant_transition(transition, 0, track); - } - field->unlock(); - delete field; -} - -// static -bool TransitionHandler::sumAudioMixAvailable() { - // TODO: remove whenever we require MLT > 6.4.x - return (LIBMLT_VERSION_MAJOR > 6 || (LIBMLT_VERSION_MAJOR == 6 && LIBMLT_VERSION_MINOR > 4)); -} - diff --git a/src/timeline/transitionhandler.h b/src/timeline/transitionhandler.h deleted file mode 100644 index 1f00972db..000000000 --- a/src/timeline/transitionhandler.h +++ /dev/null @@ -1,74 +0,0 @@ -/*************************************************************************** - * Copyright (C) 2015 by Jean-Baptiste Mardelle (jb@kdenlive.org) * - * * - * This program 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. * - * * - * This program 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 this program; if not, write to the * - * Free Software Foundation, Inc., * - * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA * - ***************************************************************************/ - -/** -* @class TransitionHandler -* @brief Manages the transitions operations in timeline -* @author Jean-Baptiste Mardelle -*/ - -#ifndef TRANSITIONHANDLER_H -#define TRANSITIONHANDLER_H - -#include "definitions.h" -#include - -class TransitionHandler : public QObject -{ - Q_OBJECT - -public: - explicit TransitionHandler(Mlt::Tractor *tractor); - bool addTransition(const QString &tag, int a_track, int b_track, GenTime in, GenTime out, const QDomElement &xml); - /** @brief Initialize transition settings if necessary and return an array of values. */ - QMap getTransitionParamsFromXml(const QDomElement &xml); - void plantTransition(Mlt::Transition &tr, int a_track, int b_track); - void plantTransition(Mlt::Field *field, Mlt::Transition &tr, int a_track, int b_track); - void cloneProperties(Mlt::Properties &dest, Mlt::Properties &source); - void updateTransition(const QString &oldTag, const QString &tag, int a_track, int b_track, GenTime in, GenTime out, const QDomElement &xml, - bool force = false); - void updateTransitionParams(const QString &type, int a_track, int b_track, GenTime in, GenTime out, const QDomElement &xml); - bool deleteTransition(const QString &tag, int a_track, int b_track, GenTime in, GenTime out, const QDomElement &xml, bool refresh = true); - void deleteTrackTransitions(int ix); - bool moveTransition(const QString &type, int startTrack, int newTrack, int newTransitionTrack, GenTime oldIn, GenTime oldOut, GenTime newIn, - GenTime newOut); - QList mltInsertTrack(int ix, const QString &name, bool videoTrack); - void duplicateTransitionOnPlaylist(int in, int out, const QString &tag, const QDomElement &xml, int a_track, int b_track, Mlt::Field *field); - /** @brief Get a transition with tag name. */ - Mlt::Transition *getTransition(const QString &name, int b_track, int a_track = -1, bool internalTransition = false) const; - /** @brief Enable/disable multitrack split view. */ - void enableMultiTrack(bool enable); - /** @brief Returns internal track transition. */ - Mlt::Transition *getTrackTransition(const QStringList &names, int b_track, int a_track) const; - /** @brief Switch track compositing mode. */ - void rebuildTransitions(int mode, const QList &videoTracks, int maxTrack); - /** @brief Returns the matching composite transition depending on the current settings. */ - static const QString compositeTransition(); - /** @brief Initialize transition settings. */ - void initTransition(const QDomElement &xml); - static bool sumAudioMixAvailable(); - -private: - Mlt::Tractor *m_tractor; - -signals: - void refresh(); -}; - -#endif