diff --git a/src/effects/effectstack/view/effectstackview.cpp b/src/effects/effectstack/view/effectstackview.cpp index 830afcf06..e271e4f8d 100644 --- a/src/effects/effectstack/view/effectstackview.cpp +++ b/src/effects/effectstack/view/effectstackview.cpp @@ -1,302 +1,305 @@ /*************************************************************************** * Copyright (C) 2017 by Jean-Baptiste Mardelle (jb@kdenlive.org) * * 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 "effectstackview.hpp" #include "assets/assetlist/view/qmltypes/asseticonprovider.hpp" #include "assets/assetpanel.hpp" #include "assets/view/assetparameterview.hpp" #include "builtstack.hpp" #include "collapsibleeffectview.hpp" #include "core.h" #include "effects/effectstack/model/effectitemmodel.hpp" #include "effects/effectstack/model/effectstackmodel.hpp" #include "kdenlivesettings.h" #include #include #include #include #include #include #include WidgetDelegate::WidgetDelegate(QObject *parent) : QStyledItemDelegate(parent) { } QSize WidgetDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const { QSize s = QStyledItemDelegate::sizeHint(option, index); if (m_height.contains(index)) { s.setHeight(m_height.value(index)); } return s; } void WidgetDelegate::setHeight(const QModelIndex &index, int height) { m_height[index] = height; emit sizeHintChanged(index); } void WidgetDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option, const QModelIndex &index) const { QStyleOptionViewItem opt(option); initStyleOption(&opt, index); QStyle *style = opt.widget ? opt.widget->style() : QApplication::style(); const int textMargin = style->pixelMetric(QStyle::PM_FocusFrameHMargin) + 1; // QRect r = QStyle::alignedRect(opt.direction, Qt::AlignVCenter | Qt::AlignLeft, opt.decorationSize, r1); style->drawPrimitive(QStyle::PE_PanelItemViewItem, &opt, painter, opt.widget); } EffectStackView::EffectStackView(AssetPanel *parent) : QWidget(parent) , m_thumbnailer(new AssetIconProvider(true)) , m_range(-1, -1) , m_model(nullptr) { setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); m_lay = new QVBoxLayout(this); m_lay->setContentsMargins(0, 0, 0, 0); m_lay->setSpacing(0); setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); setAcceptDrops(true); m_builtStack = new BuiltStack(parent); m_builtStack->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); m_lay->addWidget(m_builtStack); m_builtStack->setVisible(KdenliveSettings::showbuiltstack()); m_effectsTree = new QTreeView(this); m_effectsTree->setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::MinimumExpanding); m_effectsTree->setHeaderHidden(true); m_effectsTree->setRootIsDecorated(false); QString style = QStringLiteral("QTreeView {border: none;}"); // m_effectsTree->viewport()->setAutoFillBackground(false); m_effectsTree->setStyleSheet(style); m_effectsTree->setVisible(!KdenliveSettings::showbuiltstack()); m_lay->addWidget(m_effectsTree); m_lay->setStretch(1, 10); } EffectStackView::~EffectStackView() { delete m_thumbnailer; } void EffectStackView::dragEnterEvent(QDragEnterEvent *event) { if (event->mimeData()->hasFormat(QStringLiteral("kdenlive/effect"))) { if (event->source() == this) { event->setDropAction(Qt::MoveAction); } else { event->setDropAction(Qt::CopyAction); } event->setAccepted(true); } else { event->setAccepted(false); } } void EffectStackView::dropEvent(QDropEvent *event) { event->accept(); QString effectId = event->mimeData()->data(QStringLiteral("kdenlive/effect")); int row = m_model->rowCount(); for (int i = 0; i < m_model->rowCount(); i++) { auto item = m_model->getEffectStackRow(i); if (item->childCount() > 0) { // TODO: group continue; } std::shared_ptr eff = std::static_pointer_cast(item); QModelIndex ix = m_model->getIndexFromItem(eff); QWidget *w = m_effectsTree->indexWidget(ix); if (w && w->geometry().contains(event->pos())) { qDebug() << "// DROPPED ON EFF: " << eff->getAssetId(); row = i; break; } } if (event->source() == this) { int oldRow = event->mimeData()->data(QStringLiteral("kdenlive/effectrow")).toInt(); qDebug() << "// MOVING EFFECT FROM : " << oldRow << " TO " << row; m_model->moveEffect(row, m_model->getEffectStackRow(oldRow)); } else { if (row < m_model->rowCount()) { m_model->appendEffect(effectId); m_model->moveEffect(row, m_model->getEffectStackRow(m_model->rowCount() - 1)); } else { m_model->appendEffect(effectId); } } } void EffectStackView::setModel(std::shared_ptr model, QPair range, const QSize frameSize) { qDebug() << "MUTEX LOCK!!!!!!!!!!!! setmodel"; m_mutex.lock(); unsetModel(); m_model = model; m_sourceFrameSize = frameSize; m_effectsTree->setModel(m_model.get()); m_effectsTree->setItemDelegateForColumn(0, new WidgetDelegate(this)); m_effectsTree->setColumnHidden(1, true); m_effectsTree->setAcceptDrops(true); m_effectsTree->setDragDropMode(QAbstractItemView::DragDrop); m_effectsTree->setDragEnabled(true); m_effectsTree->setUniformRowHeights(false); m_mutex.unlock(); qDebug() << "MUTEX UNLOCK!!!!!!!!!!!! setmodel"; loadEffects(range); connect(m_model.get(), &EffectStackModel::dataChanged, this, &EffectStackView::refresh); m_builtStack->setModel(model, stackOwner()); } void EffectStackView::loadEffects(QPair range, int start, int end) { qDebug() << "MUTEX LOCK!!!!!!!!!!!! loadEffects"; QMutexLocker lock(&m_mutex); m_range = range; int max = m_model->rowCount(); if (end == -1) { end = max; } int active = m_model->getActiveEffect(); for (int i = 0; i < end; i++) { std::shared_ptr item = m_model->getEffectStackRow(i); QSize size; if (item->childCount() > 0) { // group, create sub stack continue; } std::shared_ptr effectModel = std::static_pointer_cast(item); QImage effectIcon = m_thumbnailer->requestImage(effectModel->getAssetId(), &size, QSize(QStyle::PM_SmallIconSize, QStyle::PM_SmallIconSize)); CollapsibleEffectView *view = new CollapsibleEffectView(effectModel, range, m_sourceFrameSize, effectIcon, this); qDebug() << "__ADDING EFFECT: " << effectModel->filter().get("id") << ", ACT: " << active; if (i == active) { view->slotActivateEffect(m_model->getIndexFromItem(effectModel)); } view->buttonUp->setEnabled(i > 0); view->buttonDown->setEnabled(i < max - 1); connect(view, &CollapsibleEffectView::deleteEffect, m_model.get(), &EffectStackModel::removeEffect); connect(view, &CollapsibleEffectView::moveEffect, m_model.get(), &EffectStackModel::moveEffect); connect(view, &CollapsibleEffectView::switchHeight, this, &EffectStackView::slotAdjustDelegate, Qt::DirectConnection); connect(view, &CollapsibleEffectView::startDrag, this, &EffectStackView::slotStartDrag); connect(view, &CollapsibleEffectView::createGroup, m_model.get(), &EffectStackModel::slotCreateGroup); connect(view, &CollapsibleEffectView::activateEffect, this, &EffectStackView::slotActivateEffect); connect(view, &CollapsibleEffectView::seekToPos, [this](int pos) { // at this point, the effects returns a pos relative to the clip. We need to convert it to a global time int clipIn = pCore->getItemIn(m_model->getOwnerId()); emit seekToPos(pos + clipIn); }); connect(this, &EffectStackView::doActivateEffect, view, &CollapsibleEffectView::slotActivateEffect); QModelIndex ix = m_model->getIndexFromItem(effectModel); m_effectsTree->setIndexWidget(ix, view); } qDebug() << "MUTEX UNLOCK!!!!!!!!!!!! loadEffects"; } void EffectStackView::slotActivateEffect(std::shared_ptr effectModel) { qDebug() << "MUTEX LOCK!!!!!!!!!!!! slotactivateeffect"; QMutexLocker lock(&m_mutex); m_model->setActiveEffect(effectModel->row()); QModelIndex activeIx = m_model->getIndexFromItem(effectModel); emit doActivateEffect(activeIx); qDebug() << "MUTEX UNLOCK!!!!!!!!!!!! slotactivateeffect"; } void EffectStackView::slotStartDrag(QPixmap pix, std::shared_ptr effectModel) { auto *drag = new QDrag(this); drag->setPixmap(pix); 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 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); // Start the drag and drop operation drag->exec(Qt::CopyAction | Qt::MoveAction, Qt::CopyAction); } void EffectStackView::slotAdjustDelegate(std::shared_ptr effectModel, int height) { qDebug() << "MUTEX LOCK!!!!!!!!!!!! adjustdelegate"; QMutexLocker lock(&m_mutex); QModelIndex ix = m_model->getIndexFromItem(effectModel); WidgetDelegate *del = static_cast(m_effectsTree->itemDelegate(ix)); del->setHeight(ix, height); qDebug() << "MUTEX UNLOCK!!!!!!!!!!!! adjustdelegate"; } void EffectStackView::refresh(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles) { loadEffects(m_range, topLeft.row(), bottomRight.row() + 1); } void EffectStackView::unsetModel(bool reset) { // Release ownership of smart pointer + if (m_model) { + disconnect(m_model.get(), &EffectStackModel::dataChanged, this, &EffectStackView::refresh); + } if (reset) { m_model.reset(); } } void EffectStackView::setRange(int in, int out) { qDebug() << "MUTEX LOCK!!!!!!!!!!!! setrange"; QMutexLocker lock(&m_mutex); m_range.first = in; m_range.second = out; int max = m_model->rowCount(); for (int i = 0; i < max; i++) { std::shared_ptr item = m_model->getEffectStackRow(i); std::shared_ptr eff = std::static_pointer_cast(item); QModelIndex ix = m_model->getIndexFromItem(eff); auto w = m_effectsTree->indexWidget(ix); static_cast(w)->setRange(m_range); } } ObjectId EffectStackView::stackOwner() const { if (m_model) { return m_model->getOwnerId(); } return ObjectId(ObjectType::NoItem, -1); } void EffectStackView::switchBuiltStack(bool show) { m_builtStack->setVisible(show); m_effectsTree->setVisible(!show); KdenliveSettings::setShowbuiltstack(show); }