diff --git a/src/assets/view/assetparameterview.cpp b/src/assets/view/assetparameterview.cpp
index bd8b44de5..d2d507788 100644
--- a/src/assets/view/assetparameterview.cpp
+++ b/src/assets/view/assetparameterview.cpp
@@ -1,338 +1,337 @@
/***************************************************************************
* Copyright (C) 2017 by Nicolas Carion *
* 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 "assetparameterview.hpp"
#include "assets/model/assetcommand.hpp"
#include "assets/model/assetparametermodel.hpp"
#include "assets/view/widgets/abstractparamwidget.hpp"
#include "assets/view/widgets/keyframewidget.hpp"
#include "core.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
AssetParameterView::AssetParameterView(QWidget *parent)
: QWidget(parent)
{
m_lay = new QVBoxLayout(this);
m_lay->setContentsMargins(0, 0, 0, 2);
m_lay->setSpacing(0);
setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
// Presets Combo
m_presetMenu = new QMenu(this);
- m_presetMenu->setToolTip(i18n("Presets"));
}
void AssetParameterView::setModel(const std::shared_ptr &model, QSize frameSize, bool addSpacer)
{
unsetModel();
QMutexLocker lock(&m_lock);
m_model = model;
const QString paramTag = model->getAssetId();
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/effects/presets/"));
const QString presetFile = dir.absoluteFilePath(QString("%1.json").arg(paramTag));
connect(this, &AssetParameterView::updatePresets, [this, presetFile](const QString &presetName) {
m_presetMenu->clear();
m_presetGroup.reset(new QActionGroup(this));
m_presetGroup->setExclusive(true);
m_presetMenu->addAction(QIcon::fromTheme(QStringLiteral("view-refresh")), i18n("Reset Effect"), this, SLOT(resetValues()));
// Save preset
m_presetMenu->addAction(QIcon::fromTheme(QStringLiteral("document-save-as-template")), i18n("Save preset"), this, SLOT(slotSavePreset()));
m_presetMenu->addAction(QIcon::fromTheme(QStringLiteral("document-save-as-template")), i18n("Update current preset"), this, SLOT(slotUpdatePreset()));
m_presetMenu->addAction(QIcon::fromTheme(QStringLiteral("edit-delete")), i18n("Delete preset"), this, SLOT(slotDeletePreset()));
m_presetMenu->addSeparator();
QStringList presets = m_model->getPresetList(presetFile);
for (const QString &pName : presets) {
QAction *ac = m_presetMenu->addAction(pName, this, SLOT(slotLoadPreset()));
m_presetGroup->addAction(ac);
ac->setData(pName);
ac->setCheckable(true);
if (pName == presetName) {
ac->setChecked(true);
}
}
});
emit updatePresets();
connect(m_model.get(), &AssetParameterModel::dataChanged, this, &AssetParameterView::refresh);
if (paramTag.endsWith(QStringLiteral("lift_gamma_gain"))) {
// Special case, the colorwheel widget manages several parameters
QModelIndex index = model->index(0, 0);
auto w = AbstractParamWidget::construct(model, index, frameSize, this);
connect(w, &AbstractParamWidget::valueChanged, this, &AssetParameterView::commitChanges);
m_lay->addWidget(w);
m_widgets.push_back(w);
} else {
for (int i = 0; i < model->rowCount(); ++i) {
QModelIndex index = model->index(i, 0);
auto type = model->data(index, AssetParameterModel::TypeRole).value();
if (m_mainKeyframeWidget &&
(type == ParamType::Geometry || type == ParamType::Animated || type == ParamType::RestrictedAnim || type == ParamType::KeyframeParam)) {
// Keyframe widget can have some extra params that shouldn't build a new widget
qDebug() << "// FOUND ADDED PARAM";
m_mainKeyframeWidget->addParameter(index);
} else {
auto w = AbstractParamWidget::construct(model, index, frameSize, this);
connect(this, &AssetParameterView::initKeyframeView, w, &AbstractParamWidget::slotInitMonitor);
if (type == ParamType::KeyframeParam || type == ParamType::AnimatedRect || type == ParamType::Roto_spline) {
m_mainKeyframeWidget = static_cast(w);
}
connect(w, &AbstractParamWidget::valueChanged, this, &AssetParameterView::commitChanges);
connect(w, &AbstractParamWidget::seekToPos, this, &AssetParameterView::seekToPos);
m_lay->addWidget(w);
m_widgets.push_back(w);
}
}
}
if (addSpacer) {
m_lay->addStretch();
}
}
QVector> AssetParameterView::getDefaultValues() const
{
QLocale locale;
QVector> values;
for (int i = 0; i < m_model->rowCount(); ++i) {
QModelIndex index = m_model->index(i, 0);
QString name = m_model->data(index, AssetParameterModel::NameRole).toString();
auto type = m_model->data(index, AssetParameterModel::TypeRole).value();
QVariant defaultValue = m_model->data(index, AssetParameterModel::DefaultRole);
if (type == ParamType::KeyframeParam || type == ParamType::AnimatedRect) {
QString val = type == ParamType::KeyframeParam ? locale.toString(defaultValue.toDouble()) : defaultValue.toString();
if (!val.contains(QLatin1Char('='))) {
val.prepend(QStringLiteral("%1=").arg(m_model->data(index, AssetParameterModel::ParentInRole).toInt()));
defaultValue = QVariant(val);
}
}
values.append({name, defaultValue});
}
return values;
}
void AssetParameterView::resetValues()
{
const QVector> values = getDefaultValues();
auto *command = new AssetUpdateCommand(m_model, values);
pCore->pushUndo(command);
/*if (m_mainKeyframeWidget) {
m_mainKeyframeWidget->resetKeyframes();
}*/
}
void AssetParameterView::commitChanges(const QModelIndex &index, const QString &value, bool storeUndo)
{
// Warning: please note that some widgets (for example keyframes) do NOT send the valueChanged signal and do modifications on their own
auto *command = new AssetCommand(m_model, index, value);
if (storeUndo) {
pCore->pushUndo(command);
} else {
command->redo();
delete command;
}
}
void AssetParameterView::unsetModel()
{
QMutexLocker lock(&m_lock);
if (m_model) {
// if a model is already there, we have to disconnect signals first
disconnect(m_model.get(), &AssetParameterModel::dataChanged, this, &AssetParameterView::refresh);
}
m_mainKeyframeWidget = nullptr;
// clear layout
m_widgets.clear();
QLayoutItem *child;
while ((child = m_lay->takeAt(0)) != nullptr) {
if (child->layout()) {
QLayoutItem *subchild;
while ((subchild = child->layout()->takeAt(0)) != nullptr) {
delete subchild->widget();
delete subchild->spacerItem();
}
}
delete child->widget();
delete child->spacerItem();
}
// Release ownership of smart pointer
m_model.reset();
}
void AssetParameterView::refresh(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles)
{
QMutexLocker lock(&m_lock);
if (m_widgets.size() == 0) {
// no visible param for this asset, abort
return;
}
Q_UNUSED(roles);
// We are expecting indexes that are children of the root index, which is "invalid"
Q_ASSERT(!topLeft.parent().isValid());
// We make sure the range is valid
if (m_mainKeyframeWidget) {
m_mainKeyframeWidget->slotRefresh();
} else {
auto type = m_model->data(m_model->index(topLeft.row(), 0), AssetParameterModel::TypeRole).value();
if (type == ParamType::ColorWheel) {
// Some special widgets, like colorwheel handle multiple params so we can have cases where param index row is greater than the number of widgets.
// Should be better managed
m_widgets[0]->slotRefresh();
return;
}
size_t max;
if (!bottomRight.isValid()) {
max = m_widgets.size() - 1;
} else {
max = (size_t)bottomRight.row();
}
Q_ASSERT(max < (int)m_widgets.size());
for (auto i = (size_t)topLeft.row(); i <= max; ++i) {
m_widgets[i]->slotRefresh();
}
}
}
int AssetParameterView::contentHeight() const
{
return m_lay->minimumSize().height();
}
MonitorSceneType AssetParameterView::needsMonitorEffectScene() const
{
if (m_mainKeyframeWidget) {
return m_mainKeyframeWidget->requiredScene();
}
for (int i = 0; i < m_model->rowCount(); ++i) {
QModelIndex index = m_model->index(i, 0);
auto type = m_model->data(index, AssetParameterModel::TypeRole).value();
if (type == ParamType::Geometry) {
return MonitorSceneGeometry;
}
}
return MonitorSceneDefault;
}
/*void AssetParameterView::initKeyframeView()
{
if (m_mainKeyframeWidget) {
m_mainKeyframeWidget->initMonitor();
} else {
for (int i = 0; i < m_model->rowCount(); ++i) {
QModelIndex index = m_model->index(i, 0);
auto type = m_model->data(index, AssetParameterModel::TypeRole).value();
if (type == ParamType::Geometry) {
return MonitorSceneGeometry;
}
}
}
}*/
void AssetParameterView::slotRefresh()
{
refresh(m_model->index(0, 0), m_model->index(m_model->rowCount() - 1, 0), {});
}
bool AssetParameterView::keyframesAllowed() const
{
return m_mainKeyframeWidget != nullptr;
}
bool AssetParameterView::modelHideKeyframes() const
{
return m_mainKeyframeWidget != nullptr && !m_mainKeyframeWidget->keyframesVisible();
}
void AssetParameterView::toggleKeyframes(bool enable)
{
if (m_mainKeyframeWidget) {
m_mainKeyframeWidget->showKeyframes(enable);
}
}
void AssetParameterView::slotDeletePreset()
{
QAction *ac = m_presetGroup->checkedAction();
if (!ac) {
return;
}
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/effects/presets/"));
if (!dir.exists()) {
dir.mkpath(QStringLiteral("."));
}
const QString presetFile = dir.absoluteFilePath(QString("%1.json").arg(m_model->getAssetId()));
m_model->deletePreset(presetFile, ac->data().toString());
emit updatePresets();
}
void AssetParameterView::slotUpdatePreset()
{
QAction *ac = m_presetGroup->checkedAction();
if (!ac) {
return;
}
slotSavePreset(ac->data().toString());
}
void AssetParameterView::slotSavePreset(QString presetName)
{
if (presetName.isEmpty()) {
bool ok;
presetName = QInputDialog::getText(this, i18n("Enter preset name"), i18n("Enter the name of this preset"), QLineEdit::Normal, QString(), &ok);
if (!ok) return;
}
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/effects/presets/"));
if (!dir.exists()) {
dir.mkpath(QStringLiteral("."));
}
const QString presetFile = dir.absoluteFilePath(QString("%1.json").arg(m_model->getAssetId()));
m_model->savePreset(presetFile, presetName);
emit updatePresets(presetName);
}
void AssetParameterView::slotLoadPreset()
{
auto *action = qobject_cast(sender());
if (!action) {
return;
}
const QString presetName = action->data().toString();
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/effects/presets/"));
const QString presetFile = dir.absoluteFilePath(QString("%1.json").arg(m_model->getAssetId()));
const QVector> params = m_model->loadPreset(presetFile, presetName);
auto *command = new AssetUpdateCommand(m_model, params);
pCore->pushUndo(command);
}
QMenu *AssetParameterView::presetMenu()
{
return m_presetMenu;
}
diff --git a/src/effects/effectstack/view/collapsibleeffectview.cpp b/src/effects/effectstack/view/collapsibleeffectview.cpp
index 3d296708a..60e0ec4de 100644
--- a/src/effects/effectstack/view/collapsibleeffectview.cpp
+++ b/src/effects/effectstack/view/collapsibleeffectview.cpp
@@ -1,806 +1,807 @@
/***************************************************************************
* 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 "collapsibleeffectview.hpp"
#include "assets/view/assetparameterview.hpp"
#include "core.h"
#include "dialogs/clipcreationdialog.h"
#include "effects/effectsrepository.hpp"
#include "effects/effectstack/model/effectitemmodel.hpp"
#include "kdenlivesettings.h"
#include "monitor/monitor.h"
#include "kdenlive_debug.h"
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
#include
CollapsibleEffectView::CollapsibleEffectView(const std::shared_ptr &effectModel, QSize frameSize, const QImage &icon, QWidget *parent)
: AbstractCollapsibleWidget(parent)
, m_view(nullptr)
, m_model(effectModel)
, m_regionEffect(false)
{
QString effectId = effectModel->getAssetId();
QString effectName = EffectsRepository::get()->getName(effectId);
if (effectId == QLatin1String("region")) {
m_regionEffect = true;
decoframe->setObjectName(QStringLiteral("decoframegroup"));
}
filterWheelEvent = true;
setSizePolicy(QSizePolicy::MinimumExpanding, QSizePolicy::Maximum);
// decoframe->setProperty("active", true);
// m_info.fromString(effect.attribute(QStringLiteral("kdenlive_info")));
// setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont));
buttonUp->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-up")));
buttonUp->setToolTip(i18n("Move effect up"));
buttonDown->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-down")));
buttonDown->setToolTip(i18n("Move effect down"));
buttonDel->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-deleffect")));
buttonDel->setToolTip(i18n("Delete effect"));
// buttonUp->setEnabled(canMoveUp);
// buttonDown->setEnabled(!lastEffect);
if (effectId == QLatin1String("speed")) {
// Speed effect is a "pseudo" effect, cannot be moved
buttonUp->setVisible(false);
buttonDown->setVisible(false);
m_isMovable = false;
setAcceptDrops(false);
} else {
setAcceptDrops(true);
}
// checkAll->setToolTip(i18n("Enable/Disable all effects"));
// buttonShowComments->setIcon(QIcon::fromTheme("help-about"));
// buttonShowComments->setToolTip(i18n("Show additional information for the parameters"));
m_collapse = new KDualAction(i18n("Collapse Effect"), i18n("Expand Effect"), this);
m_collapse->setActiveIcon(QIcon::fromTheme(QStringLiteral("arrow-right")));
collapseButton->setDefaultAction(m_collapse);
connect(m_collapse, &KDualAction::activeChanged, this, &CollapsibleEffectView::slotSwitch);
if (effectModel->rowCount() == 0) {
// Effect has no paramerter
m_collapse->setInactiveIcon(QIcon::fromTheme(QStringLiteral("tools-wizard")));
collapseButton->setEnabled(false);
} else {
m_collapse->setInactiveIcon(QIcon::fromTheme(QStringLiteral("arrow-down")));
}
auto *l = static_cast(frame->layout());
m_colorIcon = new QLabel(this);
l->insertWidget(0, m_colorIcon);
m_colorIcon->setFixedSize(icon.size());
title = new QLabel(this);
l->insertWidget(2, title);
m_keyframesButton = new QToolButton(this);
m_keyframesButton->setIcon(QIcon::fromTheme(QStringLiteral("adjustcurves")));
m_keyframesButton->setAutoRaise(true);
m_keyframesButton->setCheckable(true);
m_keyframesButton->setToolTip(i18n("Enable Keyframes"));
l->insertWidget(3, m_keyframesButton);
// Enable button
m_enabledButton = new KDualAction(i18n("Disable Effect"), i18n("Enable Effect"), this);
m_enabledButton->setActiveIcon(QIcon::fromTheme(QStringLiteral("hint")));
m_enabledButton->setInactiveIcon(QIcon::fromTheme(QStringLiteral("visibility")));
enabledButton->setDefaultAction(m_enabledButton);
connect(m_model.get(), &AssetParameterModel::enabledChange, this, &CollapsibleEffectView::enableView);
m_groupAction = new QAction(QIcon::fromTheme(QStringLiteral("folder-new")), i18n("Create Group"), this);
connect(m_groupAction, &QAction::triggered, this, &CollapsibleEffectView::slotCreateGroup);
if (m_regionEffect) {
effectName.append(':' + QUrl(Xml::getXmlParameter(m_effect, QStringLiteral("resource"))).fileName());
}
// Color thumb
m_colorIcon->setPixmap(QPixmap::fromImage(icon));
title->setText(effectName);
m_view = new AssetParameterView(this);
const std::shared_ptr effectParamModel = std::static_pointer_cast(effectModel);
m_view->setModel(effectParamModel, frameSize);
connect(m_view, &AssetParameterView::seekToPos, this, &AbstractCollapsibleWidget::seekToPos);
connect(this, &CollapsibleEffectView::refresh, m_view, &AssetParameterView::slotRefresh);
m_keyframesButton->setVisible(m_view->keyframesAllowed());
auto *lay = new QVBoxLayout(widgetFrame);
lay->setContentsMargins(0, 0, 0, 2);
lay->setSpacing(0);
connect(m_keyframesButton, &QToolButton::toggled, [this](bool toggle) {
m_view->toggleKeyframes(toggle);
// We need to switch twice to get a correct resize
slotSwitch(!m_model->isCollapsed());
slotSwitch(!m_model->isCollapsed());
});
lay->addWidget(m_view);
if (!effectParamModel->hasMoreThanOneKeyframe()) {
// No keyframe or only one, allow hiding
bool hideByDefault = effectParamModel->data(effectParamModel->index(0, 0), AssetParameterModel::HideKeyframesFirstRole).toBool();
if (hideByDefault) {
m_view->toggleKeyframes(false);
} else {
m_keyframesButton->setChecked(true);
}
} else {
m_keyframesButton->setChecked(true);
}
// Presets
- presetButton->setIcon(QIcon::fromTheme(QStringLiteral("document-new-from-template")));
+ presetButton->setIcon(QIcon::fromTheme(QStringLiteral("adjustlevels")));
presetButton->setMenu(m_view->presetMenu());
+ presetButton->setToolTip(i18n("Presets"));
// Main menu
m_menu = new QMenu(this);
if (effectModel->rowCount() == 0) {
collapseButton->setEnabled(false);
m_view->setVisible(false);
}
m_menu->addAction(QIcon::fromTheme(QStringLiteral("document-save")), i18n("Save Effect"), this, SLOT(slotSaveEffect()));
if (!m_regionEffect) {
/*if (m_info.groupIndex == -1) {
m_menu->addAction(m_groupAction);
}*/
m_menu->addAction(QIcon::fromTheme(QStringLiteral("folder-new")), i18n("Create Region"), this, SLOT(slotCreateRegion()));
}
// setupWidget(info, metaInfo);
menuButton->setIcon(QIcon::fromTheme(QStringLiteral("kdenlive-menu")));
menuButton->setMenu(m_menu);
if (!effectModel->isEnabled()) {
title->setEnabled(false);
m_colorIcon->setEnabled(false);
if (KdenliveSettings::disable_effect_parameters()) {
widgetFrame->setEnabled(false);
}
m_enabledButton->setActive(true);
} else {
m_enabledButton->setActive(false);
}
connect(m_enabledButton, &KDualAction::activeChangedByUser, this, &CollapsibleEffectView::slotDisable);
connect(buttonUp, &QAbstractButton::clicked, this, &CollapsibleEffectView::slotEffectUp);
connect(buttonDown, &QAbstractButton::clicked, this, &CollapsibleEffectView::slotEffectDown);
connect(buttonDel, &QAbstractButton::clicked, this, &CollapsibleEffectView::slotDeleteEffect);
Q_FOREACH (QSpinBox *sp, findChildren()) {
sp->installEventFilter(this);
sp->setFocusPolicy(Qt::StrongFocus);
}
Q_FOREACH (KComboBox *cb, findChildren()) {
cb->installEventFilter(this);
cb->setFocusPolicy(Qt::StrongFocus);
}
Q_FOREACH (QProgressBar *cb, findChildren()) {
cb->installEventFilter(this);
cb->setFocusPolicy(Qt::StrongFocus);
}
m_collapse->setActive(m_model->isCollapsed());
slotSwitch(m_model->isCollapsed());
}
CollapsibleEffectView::~CollapsibleEffectView()
{
qDebug() << "deleting collapsibleeffectview";
}
void CollapsibleEffectView::setWidgetHeight(qreal value)
{
widgetFrame->setFixedHeight(m_view->contentHeight() * value);
}
void CollapsibleEffectView::slotCreateGroup()
{
emit createGroup(m_model);
}
void CollapsibleEffectView::slotCreateRegion()
{
QString allExtensions = ClipCreationDialog::getExtensions().join(QLatin1Char(' '));
const QString dialogFilter =
allExtensions + QLatin1Char(' ') + QLatin1Char('|') + i18n("All Supported Files") + QStringLiteral("\n* ") + QLatin1Char('|') + i18n("All Files");
QString clipFolder = KRecentDirs::dir(QStringLiteral(":KdenliveClipFolder"));
if (clipFolder.isEmpty()) {
clipFolder = QDir::homePath();
}
QPointer d = new QFileDialog(QApplication::activeWindow(), QString(), clipFolder, dialogFilter);
d->setFileMode(QFileDialog::ExistingFile);
if (d->exec() == QDialog::Accepted && !d->selectedUrls().isEmpty()) {
KRecentDirs::add(QStringLiteral(":KdenliveClipFolder"), d->selectedUrls().first().adjusted(QUrl::RemoveFilename).toLocalFile());
emit createRegion(effectIndex(), d->selectedUrls().first());
}
delete d;
}
void CollapsibleEffectView::slotUnGroup()
{
emit unGroup(this);
}
bool CollapsibleEffectView::eventFilter(QObject *o, QEvent *e)
{
if (e->type() == QEvent::Enter) {
frame->setProperty("mouseover", true);
frame->setStyleSheet(frame->styleSheet());
return QWidget::eventFilter(o, e);
}
if (e->type() == QEvent::Wheel) {
auto *we = static_cast(e);
if (!filterWheelEvent || we->modifiers() != Qt::NoModifier) {
e->accept();
return false;
}
if (qobject_cast(o)) {
// if (qobject_cast(o)->focusPolicy() == Qt::WheelFocus) {
e->accept();
return false;
}
if (qobject_cast(o)) {
if (qobject_cast(o)->focusPolicy() == Qt::WheelFocus) {
e->accept();
return false;
}
e->ignore();
return true;
}
if (qobject_cast(o)) {
// if (qobject_cast(o)->focusPolicy() == Qt::WheelFocus)*/ {
e->accept();
return false;
}
}
return QWidget::eventFilter(o, e);
}
QDomElement CollapsibleEffectView::effect() const
{
return m_effect;
}
QDomElement CollapsibleEffectView::effectForSave() const
{
QDomElement effect = m_effect.cloneNode().toElement();
effect.removeAttribute(QStringLiteral("kdenlive_ix"));
/*
if (m_paramWidget) {
int in = m_paramWidget->range().x();
EffectsController::offsetKeyframes(in, effect);
}
*/
return effect;
}
bool CollapsibleEffectView::isActive() const
{
return decoframe->property("active").toBool();
}
bool CollapsibleEffectView::isEnabled() const
{
return m_enabledButton->isActive();
}
void CollapsibleEffectView::slotActivateEffect(QModelIndex ix)
{
// m_colorIcon->setEnabled(active);
bool active = ix.row() == m_model->row();
decoframe->setProperty("active", active);
decoframe->setStyleSheet(decoframe->styleSheet());
if (active) {
pCore->getMonitor(m_model->monitorId)->slotShowEffectScene(needsMonitorEffectScene());
}
m_view->initKeyframeView(active);
}
void CollapsibleEffectView::mousePressEvent(QMouseEvent *e)
{
m_dragStart = e->globalPos();
emit activateEffect(m_model);
QWidget::mousePressEvent(e);
}
void CollapsibleEffectView::mouseMoveEvent(QMouseEvent *e)
{
if ((e->globalPos() - m_dragStart).manhattanLength() < QApplication::startDragDistance()) {
QPixmap pix = frame->grab();
emit startDrag(pix, m_model);
}
QWidget::mouseMoveEvent(e);
}
void CollapsibleEffectView::mouseDoubleClickEvent(QMouseEvent *event)
{
if (frame->underMouse() && collapseButton->isEnabled()) {
event->accept();
m_collapse->setActive(!m_collapse->isActive());
} else {
event->ignore();
}
}
void CollapsibleEffectView::mouseReleaseEvent(QMouseEvent *event)
{
m_dragStart = QPoint();
if (!decoframe->property("active").toBool()) {
// emit activateEffect(effectIndex());
}
QWidget::mouseReleaseEvent(event);
}
void CollapsibleEffectView::slotDisable(bool disable)
{
QString effectId = m_model->getAssetId();
QString effectName = EffectsRepository::get()->getName(effectId);
std::static_pointer_cast(m_model)->markEnabled(effectName, !disable);
}
void CollapsibleEffectView::slotDeleteEffect()
{
emit deleteEffect(m_model);
}
void CollapsibleEffectView::slotEffectUp()
{
emit moveEffect(qMax(0, m_model->row() - 1), m_model);
}
void CollapsibleEffectView::slotEffectDown()
{
emit moveEffect(m_model->row() + 2, m_model);
}
void CollapsibleEffectView::slotSaveEffect()
{
QString name = QInputDialog::getText(this, i18n("Save Effect"), i18n("Name for saved effect: "));
if (name.trimmed().isEmpty()) {
return;
}
QDir dir(QStandardPaths::writableLocation(QStandardPaths::AppDataLocation) + QStringLiteral("/effects/"));
if (!dir.exists()) {
dir.mkpath(QStringLiteral("."));
}
if (dir.exists(name + QStringLiteral(".xml")))
if (KMessageBox::questionYesNo(this, i18n("File %1 already exists.\nDo you want to overwrite it?", name + QStringLiteral(".xml"))) == KMessageBox::No) {
return;
}
QDomDocument doc;
// Get base effect xml
QString effectId = m_model->getAssetId();
QDomElement effect = EffectsRepository::get()->getXml(effectId);
// Adjust param values
QVector> currentValues = m_model->getAllParameters();
QMap values;
QLocale locale;
for (const auto ¶m : currentValues) {
if (param.second.type() == QVariant::Double) {
values.insert(param.first, locale.toString(param.second.toDouble()));
} else {
values.insert(param.first, param.second.toString());
}
}
QDomNodeList params = effect.elementsByTagName("parameter");
for (int i = 0; i < params.count(); ++i) {
const QString paramName = params.item(i).toElement().attribute("name");
const QString paramType = params.item(i).toElement().attribute("type");
if (paramType == QLatin1String("fixed") || !values.contains(paramName)) {
continue;
}
params.item(i).toElement().setAttribute(QStringLiteral("value"), values.value(paramName));
}
doc.appendChild(doc.importNode(effect, true));
effect = doc.firstChild().toElement();
effect.removeAttribute(QStringLiteral("kdenlive_ix"));
effect.setAttribute(QStringLiteral("id"), name);
effect.setAttribute(QStringLiteral("type"), QStringLiteral("custom"));
/*
if (m_paramWidget) {
int in = m_paramWidget->range().x();
EffectsController::offsetKeyframes(in, effect);
}
*/
QDomElement effectname = effect.firstChildElement(QStringLiteral("name"));
effect.removeChild(effectname);
effectname = doc.createElement(QStringLiteral("name"));
QDomText nametext = doc.createTextNode(name);
effectname.appendChild(nametext);
effect.insertBefore(effectname, QDomNode());
QDomElement effectprops = effect.firstChildElement(QStringLiteral("properties"));
effectprops.setAttribute(QStringLiteral("id"), name);
effectprops.setAttribute(QStringLiteral("type"), QStringLiteral("custom"));
QFile file(dir.absoluteFilePath(name + QStringLiteral(".xml")));
if (file.open(QFile::WriteOnly | QFile::Truncate)) {
QTextStream out(&file);
out << doc.toString();
}
file.close();
emit reloadEffect(dir.absoluteFilePath(name + QStringLiteral(".xml")));
}
void CollapsibleEffectView::slotResetEffect()
{
m_view->resetValues();
}
void CollapsibleEffectView::slotSwitch(bool collapse)
{
widgetFrame->setFixedHeight(collapse ? 0 : m_view->sizeHint().height());
setFixedHeight(widgetFrame->height() + frame->height() + (2 * decoframe->lineWidth()));
// m_view->setVisible(!collapse);
emit switchHeight(m_model, height());
m_model->setCollapsed(collapse);
}
void CollapsibleEffectView::animationChanged(const QVariant &geom)
{
parentWidget()->setFixedHeight(geom.toRect().height());
}
void CollapsibleEffectView::animationFinished()
{
if (m_collapse->isActive()) {
widgetFrame->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
} else {
widgetFrame->setFixedHeight(m_view->contentHeight());
}
}
void CollapsibleEffectView::setGroupIndex(int ix)
{
Q_UNUSED(ix)
/*if (m_info.groupIndex == -1 && ix != -1) {
m_menu->removeAction(m_groupAction);
} else if (m_info.groupIndex != -1 && ix == -1) {
m_menu->addAction(m_groupAction);
}
m_info.groupIndex = ix;
m_effect.setAttribute(QStringLiteral("kdenlive_info"), m_info.toString());*/
}
void CollapsibleEffectView::setGroupName(const QString &groupName){
Q_UNUSED(groupName)
/*m_info.groupName = groupName;
m_effect.setAttribute(QStringLiteral("kdenlive_info"), m_info.toString());*/
}
QString CollapsibleEffectView::infoString() const
{
return QString(); // m_info.toString();
}
void CollapsibleEffectView::removeFromGroup()
{
/*if (m_info.groupIndex != -1) {
m_menu->addAction(m_groupAction);
}
m_info.groupIndex = -1;
m_info.groupName.clear();
m_effect.setAttribute(QStringLiteral("kdenlive_info"), m_info.toString());
emit parameterChanged(m_original_effect, m_effect, effectIndex());*/
}
int CollapsibleEffectView::groupIndex() const
{
return -1; // m_info.groupIndex;
}
int CollapsibleEffectView::effectIndex() const
{
if (m_effect.isNull()) {
return -1;
}
return m_effect.attribute(QStringLiteral("kdenlive_ix")).toInt();
}
void CollapsibleEffectView::updateWidget(const ItemInfo &info, const QDomElement &effect)
{
// cleanup
/*
delete m_paramWidget;
m_paramWidget = nullptr;
*/
m_effect = effect;
setupWidget(info);
}
void CollapsibleEffectView::updateFrameInfo()
{
/*
if (m_paramWidget) {
m_paramWidget->refreshFrameInfo();
}
*/
}
void CollapsibleEffectView::setActiveKeyframe(int kf)
{
Q_UNUSED(kf)
/*
if (m_paramWidget) {
m_paramWidget->setActiveKeyframe(kf);
}
*/
}
void CollapsibleEffectView::setupWidget(const ItemInfo &info)
{
Q_UNUSED(info)
/*
if (m_effect.isNull()) {
// //qCDebug(KDENLIVE_LOG) << "// EMPTY EFFECT STACK";
return;
}
delete m_paramWidget;
m_paramWidget = nullptr;
if (m_effect.attribute(QStringLiteral("tag")) == QLatin1String("region")) {
m_regionEffect = true;
QDomNodeList effects = m_effect.elementsByTagName(QStringLiteral("effect"));
QDomNodeList origin_effects = m_original_effect.elementsByTagName(QStringLiteral("effect"));
m_paramWidget = new ParameterContainer(m_effect, info, metaInfo, widgetFrame);
QWidget *container = new QWidget(widgetFrame);
QVBoxLayout *vbox = static_cast(widgetFrame->layout());
vbox->addWidget(container);
// m_paramWidget = new ParameterContainer(m_effect.toElement(), info, metaInfo, container);
for (int i = 0; i < effects.count(); ++i) {
bool canMoveUp = true;
if (i == 0 || effects.at(i - 1).toElement().attribute(QStringLiteral("id")) == QLatin1String("speed")) {
canMoveUp = false;
}
CollapsibleEffectView *coll = new CollapsibleEffectView(effects.at(i).toElement(), origin_effects.at(i).toElement(), info, metaInfo, canMoveUp,
i == effects.count() - 1, container);
m_subParamWidgets.append(coll);
connect(coll, &CollapsibleEffectView::parameterChanged, this, &CollapsibleEffectView::slotUpdateRegionEffectParams);
// container = new QWidget(widgetFrame);
vbox->addWidget(coll);
// p = new ParameterContainer(effects.at(i).toElement(), info, isEffect, container);
}
} else {
m_paramWidget = new ParameterContainer(m_effect, info, metaInfo, widgetFrame);
connect(m_paramWidget, &ParameterContainer::disableCurrentFilter, this, &CollapsibleEffectView::slotDisable);
connect(m_paramWidget, &ParameterContainer::importKeyframes, this, &CollapsibleEffectView::importKeyframes);
if (m_effect.firstChildElement(QStringLiteral("parameter")).isNull()) {
// Effect has no parameter, don't allow expand
collapseButton->setEnabled(false);
collapseButton->setVisible(false);
widgetFrame->setVisible(false);
}
}
if (collapseButton->isEnabled() && m_info.isCollapsed) {
widgetFrame->setVisible(false);
collapseButton->setArrowType(Qt::RightArrow);
}
connect(m_paramWidget, &ParameterContainer::parameterChanged, this, &CollapsibleEffectView::parameterChanged);
connect(m_paramWidget, &ParameterContainer::startFilterJob, this, &CollapsibleEffectView::startFilterJob);
connect(this, &CollapsibleEffectView::syncEffectsPos, m_paramWidget, &ParameterContainer::syncEffectsPos);
connect(m_paramWidget, &ParameterContainer::checkMonitorPosition, this, &CollapsibleEffectView::checkMonitorPosition);
connect(m_paramWidget, &ParameterContainer::seekTimeline, this, &CollapsibleEffectView::seekTimeline);
connect(m_paramWidget, &ParameterContainer::importClipKeyframes, this, &CollapsibleEffectView::prepareImportClipKeyframes);
*/
}
bool CollapsibleEffectView::isGroup() const
{
return false;
}
void CollapsibleEffectView::updateTimecodeFormat()
{
/*
m_paramWidget->updateTimecodeFormat();
if (!m_subParamWidgets.isEmpty()) {
// we have a group
for (int i = 0; i < m_subParamWidgets.count(); ++i) {
m_subParamWidgets.at(i)->updateTimecodeFormat();
}
}
*/
}
void CollapsibleEffectView::slotUpdateRegionEffectParams(const QDomElement & /*old*/, const QDomElement & /*e*/, int /*ix*/)
{
// qCDebug(KDENLIVE_LOG)<<"// EMIT CHANGE SUBEFFECT.....:";
emit parameterChanged(m_original_effect, m_effect, effectIndex());
}
void CollapsibleEffectView::slotSyncEffectsPos(int pos)
{
emit syncEffectsPos(pos);
}
void CollapsibleEffectView::dragEnterEvent(QDragEnterEvent *event)
{
Q_UNUSED(event)
/*
if (event->mimeData()->hasFormat(QStringLiteral("kdenlive/effectslist"))) {
frame->setProperty("target", true);
frame->setStyleSheet(frame->styleSheet());
event->acceptProposedAction();
} else if (m_paramWidget->doesAcceptDrops() && event->mimeData()->hasFormat(QStringLiteral("kdenlive/geometry")) &&
event->source()->objectName() != QStringLiteral("ParameterContainer")) {
event->setDropAction(Qt::CopyAction);
event->setAccepted(true);
} else {
QWidget::dragEnterEvent(event);
}
*/
}
void CollapsibleEffectView::dragLeaveEvent(QDragLeaveEvent * /*event*/)
{
frame->setProperty("target", false);
frame->setStyleSheet(frame->styleSheet());
}
void CollapsibleEffectView::importKeyframes(const QString &kf)
{
QMap keyframes;
if (kf.contains(QLatin1Char('\n'))) {
const QStringList params = kf.split(QLatin1Char('\n'), QString::SkipEmptyParts);
for (const QString ¶m : params) {
keyframes.insert(param.section(QLatin1Char('='), 0, 0), param.section(QLatin1Char('='), 1));
}
} else {
keyframes.insert(kf.section(QLatin1Char('='), 0, 0), kf.section(QLatin1Char('='), 1));
}
emit importClipKeyframes(AVWidget, m_itemInfo, m_effect.cloneNode().toElement(), keyframes);
}
void CollapsibleEffectView::dropEvent(QDropEvent *event)
{
if (event->mimeData()->hasFormat(QStringLiteral("kdenlive/geometry"))) {
if (event->source()->objectName() == QStringLiteral("ParameterContainer")) {
return;
}
// emit activateEffect(effectIndex());
QString itemData = event->mimeData()->data(QStringLiteral("kdenlive/geometry"));
importKeyframes(itemData);
return;
}
frame->setProperty("target", false);
frame->setStyleSheet(frame->styleSheet());
const QString effects = QString::fromUtf8(event->mimeData()->data(QStringLiteral("kdenlive/effectslist")));
// event->acceptProposedAction();
QDomDocument doc;
doc.setContent(effects, true);
QDomElement e = doc.documentElement();
int ix = e.attribute(QStringLiteral("kdenlive_ix")).toInt();
int currentEffectIx = effectIndex();
if (ix == currentEffectIx || e.attribute(QStringLiteral("id")) == QLatin1String("speed")) {
// effect dropped on itself, or unmovable speed dropped, reject
event->ignore();
return;
}
if (ix == 0 || e.tagName() == QLatin1String("effectgroup")) {
if (e.tagName() == QLatin1String("effectgroup")) {
// moving a group
QDomNodeList subeffects = e.elementsByTagName(QStringLiteral("effect"));
if (subeffects.isEmpty()) {
event->ignore();
return;
}
event->setDropAction(Qt::MoveAction);
event->accept();
/*
EffectInfo info;
info.fromString(subeffects.at(0).toElement().attribute(QStringLiteral("kdenlive_info")));
if (info.groupIndex >= 0) {
// Moving group
QList effectsIds;
// Collect moved effects ids
for (int i = 0; i < subeffects.count(); ++i) {
QDomElement effect = subeffects.at(i).toElement();
effectsIds << effect.attribute(QStringLiteral("kdenlive_ix")).toInt();
}
// emit moveEffect(effectsIds, currentEffectIx, info.groupIndex, info.groupName);
} else {
// group effect dropped from effect list
if (m_info.groupIndex > -1) {
// TODO: Should we merge groups??
}
emit addEffect(e);
}*/
emit addEffect(e);
return;
}
// effect dropped from effects list, add it
e.setAttribute(QStringLiteral("kdenlive_ix"), ix);
/*if (m_info.groupIndex > -1) {
// Dropped on a group
e.setAttribute(QStringLiteral("kdenlive_info"), m_info.toString());
}*/
event->setDropAction(Qt::CopyAction);
event->accept();
emit addEffect(e);
return;
}
// emit moveEffect(QList() << ix, currentEffectIx, m_info.groupIndex, m_info.groupName);
event->setDropAction(Qt::MoveAction);
event->accept();
}
void CollapsibleEffectView::adjustButtons(int ix, int max)
{
buttonUp->setEnabled(ix > 0);
buttonDown->setEnabled(ix < max - 1);
}
MonitorSceneType CollapsibleEffectView::needsMonitorEffectScene() const
{
if (!m_model->isEnabled() || !m_view) {
return MonitorSceneDefault;
}
return m_view->needsMonitorEffectScene();
}
void CollapsibleEffectView::setKeyframes(const QString &tag, const QString &keyframes)
{
Q_UNUSED(tag)
Q_UNUSED(keyframes)
/*
m_paramWidget->setKeyframes(tag, keyframes);
*/
}
bool CollapsibleEffectView::isMovable() const
{
return m_isMovable;
}
void CollapsibleEffectView::prepareImportClipKeyframes()
{
emit importClipKeyframes(AVWidget, m_itemInfo, m_effect.cloneNode().toElement(), QMap());
}
void CollapsibleEffectView::enableView(bool enabled)
{
m_enabledButton->setActive(enabled);
title->setEnabled(!enabled);
m_colorIcon->setEnabled(!enabled);
if (enabled) {
if (KdenliveSettings::disable_effect_parameters()) {
widgetFrame->setEnabled(false);
}
} else {
widgetFrame->setEnabled(true);
}
}