Members of the KDE Community are recommended to subscribe to the kde-community mailing list at https://mail.kde.org/mailman/listinfo/kde-community to allow them to participate in important discussions and receive other important announcements

implement bin effects & drag/drop of effects from timeline to bin

parent ea9e9895
......@@ -600,7 +600,7 @@ Bin::Bin(QWidget *parent)
connect(m_proxyModel, &ProjectSortProxyModel::selectModel, this, &Bin::selectProxyModel);
connect(m_itemModel.get(), SIGNAL(itemDropped(QStringList, QModelIndex)), this, SLOT(slotItemDropped(QStringList, QModelIndex)));
connect(m_itemModel.get(), SIGNAL(itemDropped(QList<QUrl>, QModelIndex)), this, SLOT(slotItemDropped(QList<QUrl>, QModelIndex)));
connect(m_itemModel.get(), SIGNAL(effectDropped(QString, QModelIndex)), this, SLOT(slotEffectDropped(QString, QModelIndex)));
connect(m_itemModel.get(), &ProjectItemModel::effectDropped, this, &Bin::slotEffectDropped);
connect(m_itemModel.get(), &QAbstractItemModel::dataChanged, this, &Bin::slotItemEdited);
connect(m_itemModel.get(), &ProjectItemModel::addClipCut, this, &Bin::slotAddClipCut);
connect(this, &Bin::refreshPanel, this, &Bin::doRefreshPanel);
......@@ -2406,7 +2406,7 @@ void Bin::slotItemDropped(const QStringList &ids, const QModelIndex &parent)
m_doc->commandStack()->push(moveCommand);
}
void Bin::slotEffectDropped(QString id, const QString &effectId)
void Bin::slotAddEffect(QString id, const QString &effectId)
{
if (id.isEmpty()) {
id = m_monitor->activeClipId();
......@@ -2420,7 +2420,7 @@ void Bin::slotEffectDropped(QString id, const QString &effectId)
}
}
void Bin::slotEffectDropped(const QString &effect, const QModelIndex &parent)
void Bin::slotEffectDropped(const QStringList &effectData, const QModelIndex &parent)
{
if (parent.isValid()) {
std::shared_ptr<AbstractProjectItem> parentItem = m_itemModel->getBinItemByIndex(parent);
......@@ -2437,7 +2437,13 @@ void Bin::slotEffectDropped(const QString &effect, const QModelIndex &parent)
QItemSelectionModel::Select);
}
setCurrent(parentItem);
std::static_pointer_cast<ProjectClip>(parentItem)->addEffect(effect);
if (effectData.count() == 4) {
// Paste effect from another stack
std::shared_ptr<EffectStackModel> sourceStack = pCore->getItemEffectStack(effectData.at(1).toInt(), effectData.at(2).toInt());
std::static_pointer_cast<ProjectClip>(parentItem)->copyEffect(sourceStack, effectData.at(3).toInt());
} else {
std::static_pointer_cast<ProjectClip>(parentItem)->addEffect(effectData.constFirst());
}
}
}
......@@ -2449,11 +2455,15 @@ void Bin::editMasterEffect(std::shared_ptr<AbstractProjectItem> clip)
}
if (clip) {
if (clip->itemType() == AbstractProjectItem::ClipItem) {
emit requestShowEffectStack(std::static_pointer_cast<ProjectClip>(clip)->getEffectStack());
std::shared_ptr<ProjectClip>clp = std::static_pointer_cast<ProjectClip>(clip);
emit requestShowEffectStack(clp->clipName(), clp->m_effectStack, QPair<int, int>(0, clp->frameDuration()));
return;
}
if (clip->itemType() == AbstractProjectItem::SubClipItem) {
if (auto ptr = clip->parentItem().lock()) emit requestShowEffectStack(std::static_pointer_cast<ProjectClip>(ptr)->getEffectStack());
if (auto ptr = clip->parentItem().lock()) {
std::shared_ptr<ProjectClip>clp = std::static_pointer_cast<ProjectClip>(ptr);
emit requestShowEffectStack(clp->clipName(), clp->m_effectStack, QPair<int, int>(0, clp->frameDuration()));
}
return;
}
}
......@@ -3518,10 +3528,12 @@ QVariantList Bin::audioFrameCache(const QString &id)
void Bin::setCurrent(std::shared_ptr<AbstractProjectItem> item)
{
switch (item->itemType()) {
case AbstractProjectItem::ClipItem:
case AbstractProjectItem::ClipItem: {
openProducer(std::static_pointer_cast<ProjectClip>(item));
requestShowEffectStack(std::static_pointer_cast<ProjectClip>(item)->getEffectStack());
std::shared_ptr<ProjectClip>clp = std::static_pointer_cast<ProjectClip>(item);
emit requestShowEffectStack(clp->clipName(), clp->m_effectStack, QPair<int, int>(0, clp->frameDuration()));
break;
}
case AbstractProjectItem::SubClipItem: {
auto subClip = std::static_pointer_cast<ProjectSubClip>(item);
QPoint zone = subClip->zone();
......@@ -3547,3 +3559,11 @@ void Bin::prepareTimelineReplacement(const requestClipInfo &info)
slotProducerReady(info, nullptr);
clip->replaceInTimeline();
}
std::shared_ptr<EffectStackModel> Bin::getClipEffectStack(int itemId)
{
std::shared_ptr<ProjectClip> clip = m_itemModel->getClipByBinID(QString::number(itemId));
Q_ASSERT(clip != nullptr);
std::shared_ptr<EffectStackModel> effectStack = std::static_pointer_cast<ClipController>(clip)->m_effectStack;
return effectStack;
}
......@@ -340,7 +340,7 @@ private slots:
void slotSaveHeaders();
void slotItemDropped(const QStringList &ids, const QModelIndex &parent);
void slotItemDropped(const QList<QUrl> &urls, const QModelIndex &parent);
void slotEffectDropped(const QString &effect, const QModelIndex &parent);
void slotEffectDropped(const QStringList &effectData, const QModelIndex &parent);
void slotItemEdited(const QModelIndex &, const QModelIndex &, const QVector<int> &);
void slotAddUrl(const QString &url, int folderId, const QMap<QString, QString> &data = QMap<QString, QString>());
void slotAddUrl(const QString &url, const QMap<QString, QString> &data = QMap<QString, QString>());
......@@ -419,7 +419,7 @@ public slots:
/** @brief Pass some important properties to timeline track producers. */
void updateTimelineProducers(const QString &id, const QMap<QString, QString> &passProperties);
/** @brief Add effect to active Bin clip (used when double clicking an effect in list). */
void slotEffectDropped(QString id, const QString &effectID);
void slotAddEffect(QString id, const QString &effectID);
/** @brief Request current frame from project monitor.
* @param clipId is the id of a clip we want to hide from screenshot
* @param request true to start capture process, false to end it. It is necessary to emit a false after image is received
......@@ -437,8 +437,10 @@ public slots:
void slotAddClipToProject(const QUrl &url);
void doUpdateThumbsProgress(long ms);
void droppedUrls(const QList<QUrl> &urls, const QStringList &folderInfo = QStringList());
/** @brief A cli producer was changed and needs to be replaced in timeline. */
/** @brief A clip producer was changed and needs to be replaced in timeline. */
void prepareTimelineReplacement(const requestClipInfo &info);
/** @brief Returns the effectstack of a given clip. */
std::shared_ptr<EffectStackModel> getClipEffectStack(int itemId);
protected:
/* This function is called whenever an item is selected to propagate signals
(for ex request to show the clip in the monitor)
......@@ -529,7 +531,7 @@ signals:
/** @brief Trigger timecode format refresh where needed. */
void refreshTimeCode();
/** @brief Request display of effect stack for a Bin clip. */
void requestShowEffectStack(std::shared_ptr<EffectStackModel>);
void requestShowEffectStack(const QString &clipName, std::shared_ptr<EffectStackModel>, QPair<int, int> range);
/** @brief Request that the current effect stack is hidden */
void requestHideEffectStack();
/** @brief Request that the given clip is displayed in the clip monitor */
......
......@@ -168,10 +168,13 @@ bool ProjectItemModel::dropMimeData(const QMimeData *data, Qt::DropAction action
return true;
}
if (data->hasFormat(QStringLiteral("kdenlive/effectslist"))) {
if (data->hasFormat(QStringLiteral("kdenlive/effect"))) {
// Dropping effect on a Bin item
const QString effect = QString::fromUtf8(data->data(QStringLiteral("kdenlive/effectslist")));
emit effectDropped(effect, parent);
QStringList effectData;
effectData << QString::fromUtf8(data->data(QStringLiteral("kdenlive/effect")));
QStringList source = QString::fromUtf8(data->data(QStringLiteral("kdenlive/effectsource"))).split(QLatin1Char('-'));
effectData << source;
emit effectDropped(effectData, parent);
return true;
}
......@@ -224,7 +227,7 @@ QStringList ProjectItemModel::mimeTypes() const
{
QStringList types;
types << QStringLiteral("kdenlive/producerslist") << QStringLiteral("text/uri-list") << QStringLiteral("kdenlive/clip")
<< QStringLiteral("kdenlive/effectslist");
<< QStringLiteral("kdenlive/effect");
return types;
}
......
......@@ -183,7 +183,7 @@ signals:
void markersNeedUpdate(const QString &id, const QList<int> &);
void itemDropped(const QStringList &, const QModelIndex &);
void itemDropped(const QList<QUrl> &, const QModelIndex &);
void effectDropped(const QString &, const QModelIndex &);
void effectDropped(const QStringList &, const QModelIndex &);
void addClipCut(const QString &, int, int);
};
......
......@@ -386,3 +386,19 @@ void Core::adjustAssetRange(int itemId, int in, int out)
{
m_mainWindow->adjustAssetPanelRange(itemId, in, out);
}
std::shared_ptr<EffectStackModel> Core::getItemEffectStack(int itemType, int itemId)
{
switch (itemType) {
case (int) ObjectType::TimelineClip:
return m_mainWindow->getCurrentTimeline()->controller()->getModel()->getClipEffectStack(itemId);
case (int) ObjectType::TimelineTrack:
//TODO
return nullptr;
break;
case (int) ObjectType::BinClip:
return m_binWidget->getClipEffectStack(itemId);
default:
return nullptr;
}
}
......@@ -30,6 +30,7 @@ class ProducerQueue;
class ProfileModel;
class ProjectManager;
class Monitor;
class EffectStackModel;
namespace Mlt {
class Repository;
......@@ -136,6 +137,8 @@ public:
/** @brief Clear asset view if itemId is displayed. */
void clearAssetPanel(int itemId);
void adjustAssetRange(int itemId, int in, int out);
/** @brief Returns the effectstack of a given bin clip. */
std::shared_ptr<EffectStackModel> getItemEffectStack(int itemType, int itemId);
private:
explicit Core();
......
......@@ -203,8 +203,14 @@ void EffectStackView::slotStartDrag(QPixmap pix, std::shared_ptr<EffectItemModel
auto *mime = new QMimeData;
mime->setData(QStringLiteral("kdenlive/effect"), effectModel->getAssetId().toUtf8());
// TODO this will break if source effect is not on the stack of a timeline clip
mime->setData(QStringLiteral("kdenlive/effectsource"), QString::number(effectModel->getOwnerId().second).toUtf8());
mime->setData(QStringLiteral("kdenlive/effectrow"), QString::number(effectModel->row()).toUtf8());
QByteArray effectSource;
effectSource += QString::number((int) effectModel->getOwnerId().first).toUtf8();
effectSource += '-';
effectSource += QString::number((int) effectModel->getOwnerId().second).toUtf8();
effectSource += '-';
effectSource += QString::number(effectModel->row()).toUtf8();
mime->setData(QStringLiteral("kdenlive/effectsource"), effectSource);
//mime->setData(QStringLiteral("kdenlive/effectrow"), QString::number(effectModel->row()).toUtf8());
// Assign ownership of the QMimeData object to the QDrag object.
drag->setMimeData(mime);
......
......@@ -314,6 +314,7 @@ void MainWindow::init()
connect(m_timelineTabs, &TimelineTabs::showTransitionModel, m_assetPanel, &AssetPanel::showTransition);
connect(m_timelineTabs, &TimelineTabs::showClipEffectStack, m_assetPanel, &AssetPanel::showEffectStack);
connect(pCore->bin(), &Bin::requestShowEffectStack, m_assetPanel, &AssetPanel::showEffectStack);
connect(this, &MainWindow::clearAssetPanel, m_assetPanel, &AssetPanel::clearAssetPanel);
connect(this, &MainWindow::adjustAssetPanelRange, m_assetPanel, &AssetPanel::adjustAssetPanelRange);
......
......@@ -52,6 +52,7 @@ ClipController::ClipController(std::shared_ptr<BinController> bincontroller, std
, m_hasLimitedDuration(true)
, m_binController(bincontroller)
, m_snapMarkers(QList<CommentedTime>())
, m_effectStack(EffectStackModel::construct(producer, {ObjectType::BinClip, m_properties->get_int("kdenlive:id")}))
{
if (!m_masterProducer->is_valid()) {
qCDebug(KDENLIVE_LOG) << "// WARNING, USING INVALID PRODUCER";
......@@ -123,6 +124,7 @@ void ClipController::addMasterProducer(const std::shared_ptr<Mlt::Producer> &pro
}
m_masterProducer = producer;
m_properties = new Mlt::Properties(m_masterProducer->get_properties());
m_effectStack = EffectStackModel::construct(producer, {ObjectType::BinClip, m_properties->get_int("kdenlive:id")});
if (!m_masterProducer->is_valid()) {
m_masterProducer = ClipController::mediaUnavailable;
m_producerLock.unlock();
......@@ -902,6 +904,12 @@ void ClipController::addEffect(const QString &effectId)
m_effectStack->appendEffect(effectId);
}
bool ClipController::copyEffect(std::shared_ptr<EffectStackModel> stackModel, int rowId)
{
m_effectStack->copyEffect(stackModel->getEffectStackRow(rowId));
return true;
}
std::shared_ptr<MarkerListModel> ClipController::getMarkerModel() const
{
return m_markerModel;
......
......@@ -34,6 +34,7 @@ along with this program. If not, see <http://www.gnu.org/licenses/>.
#include <mlt++/Mlt.h>
class QPixmap;
class Bin;
class BinController;
class AudioStreamInfo;
class EffectStackModel;
......@@ -49,6 +50,7 @@ class MarkerListModel;
class ClipController
{
public:
friend class Bin;
/**
@brief Constructs a clipController and returns a ptr to it.
* It also take care of registration to the BinController
......@@ -189,6 +191,7 @@ public:
Mlt::Properties &properties();
void initEffect(const ProfileInfo &pInfo, QDomElement &xml);
void addEffect(const ProfileInfo &pInfo, QDomElement &xml);
bool copyEffect(std::shared_ptr<EffectStackModel> stackModel, int rowId);
void removeEffect(int effectIndex, bool delayRefresh = false);
EffectsList effectList();
/** @brief Enable/disable an effect. */
......
......@@ -871,9 +871,14 @@ void ProjectManager::updateTimeline()
m_mainTimelineModel->setUndoStack(m_project->commandStack());
}
void ProjectManager::activateAsset(const QVariantMap data)
void ProjectManager::activateAsset(const QVariantMap effectData)
{
pCore->window()->getMainTimeline()->controller()->addAsset(data);
if (pCore->monitorManager()->projectMonitor()->isActive()) {
pCore->window()->getMainTimeline()->controller()->addAsset(effectData);
} else {
QString effect = effectData.value(QStringLiteral("kdenlive/effect")).toString();
pCore->bin()->slotAddEffect(QString(), effect);
}
}
......
......@@ -135,7 +135,7 @@ public slots:
/** @brief Project's duration changed, adjust monitor, etc. */
void adjustProjectDuration();
/** @brief Add an asset in timeline (effect, transition). */
void activateAsset(const QVariantMap data);
void activateAsset(const QVariantMap effectData);
private slots:
void slotRevert();
......
......@@ -1029,10 +1029,21 @@ bool TimelineModel::addClipEffect(int clipId, const QString &effectId)
return m_allClips.at(clipId)->addEffect(effectId);
}
bool TimelineModel::copyClipEffect(int clipId, const QString &sourceId, const QString &rowId)
std::shared_ptr<EffectStackModel> TimelineModel::getClipEffectStack(int itemId)
{
Q_ASSERT(m_allClips.count(clipId) > 0 && m_allClips.count(sourceId.toInt()) > 0);
return m_allClips.at(clipId)->copyEffect(m_allClips.at(sourceId.toInt())->m_effectStack, rowId.toInt());
Q_ASSERT(m_allClips.count(itemId));
return m_allClips.at(itemId)->m_effectStack;
}
bool TimelineModel::copyClipEffect(int clipId, const QString &sourceId)
{
QStringList source = sourceId.split(QLatin1Char('-'));
Q_ASSERT(m_allClips.count(clipId) && source.count() == 3);
int itemType = source.at(0).toInt();
int itemId = source.at(1).toInt();
int itemRow = source.at(2).toInt();
std::shared_ptr<EffectStackModel> effectStack = pCore->getItemEffectStack(itemType, itemId);
return m_allClips.at(clipId)->copyEffect(effectStack, itemRow);;
}
std::shared_ptr<CompositionModel> TimelineModel::getCompositionPtr(int compoId) const
......
......@@ -181,7 +181,7 @@ public:
*/
Q_INVOKABLE int getClipPosition(int clipId) const;
Q_INVOKABLE bool addClipEffect(int clipId, const QString &effectId);
Q_INVOKABLE bool copyClipEffect(int clipId, const QString &sourceId, const QString &rowId);
Q_INVOKABLE bool copyClipEffect(int clipId, const QString &sourceId);
/* @brief Returns the closest snap point within snapDistance
*/
......@@ -474,6 +474,8 @@ public:
void requestClipReload(int clipId);
/** @brief Returns the effectstack of a given clip. */
std::shared_ptr<EffectStackModel> getClipEffectStack(int itemId);
protected:
/* @brief Register a new track. This is a call-back meant to be called from TrackModel
@param pos indicates the number of the track we are adding. If this is -1, then we add at the end.
......
......@@ -138,7 +138,6 @@ Rectangle {
onEntered: {
dropData = drag.getDataAsString('kdenlive/effect')
dropSource = drag.getDataAsString('kdenlive/effectsource')
dropRow = drag.getDataAsString('kdenlive/effectrow')
}
onDropped: {
console.log("Add effect: ", dropData)
......@@ -146,7 +145,7 @@ Rectangle {
// drop from effects list
controller.addClipEffect(clipRoot.clipId, dropData);
} else {
controller.copyClipEffect(clipRoot.clipId, dropSource, dropRow);
controller.copyClipEffect(clipRoot.clipId, dropSource);
}
dropSource = ''
dropRow = -1
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment