diff --git a/data/effects/CMakeLists.txt b/data/effects/CMakeLists.txt index b90cc4180..764e5c6b2 100644 --- a/data/effects/CMakeLists.txt +++ b/data/effects/CMakeLists.txt @@ -1,138 +1,138 @@ INSTALL (FILES audiowave.xml audiowaveform.xml automask.xml audiobalance.xml audiopan.xml boxblur.xml brightness.xml channelcopy.xml charcoal.xml chroma_hold.xml chroma.xml crop.xml dust.xml dynamictext.xml freeze.xml gamma.xml grain.xml greyscale.xml invert.xml loudness.xml luma.xml mirror.xml mute.xml normalise.xml oldfilm.xml pan_zoom.xml obscure.xml region.xml rotation.xml rotation_keyframable.xml scratchlines.xml sepia.xml sox_bass.xml sox_gain.xml sox_phaser.xml sox_band.xml sox_echo.xml sox_flanger.xml sox_stretch.xml threshold.xml volume.xml wave.xml fadein.xml fadeout.xml frei0r_alpha0ps.xml frei0r_alphagrad.xml frei0r_alphaspot.xml frei0r_balanc0r.xml frei0r_baltan.xml frei0r_bezier_curves.xml frei0r_brightness.xml frei0r_cartoon.xml frei0r_cluster.xml frei0r_colgate.xml frei0r_coloradj_rgb.xml frei0r_colordistance.xml frei0r_colortap.xml frei0r_contrast0r.xml frei0r_c0rners.xml frei0r_curves.xml frei0r_d90stairsteppingfix.xml frei0r_defish0r.xml frei0r_delay0r.xml frei0r_delaygrab.xml frei0r_distort0r.xml frei0r_edgeglow.xml frei0r_equaliz0r.xml frei0r_flippo.xml frei0r_glow.xml frei0r_hqdn3d.xml frei0r_hueshift0r.xml frei0r_iirblur.xml frei0r_keyspillm0pup.xml frei0r_lenscorrection.xml frei0r_letterb0xed.xml frei0r_levels.xml frei0r_lightgraffiti.xml frei0r_luminance.xml frei0r_mask0mate.xml frei0r_medians.xml frei0r_nervous.xml frei0r_nosync0r.xml frei0r_pixeliz0r.xml frei0r_pr0be.xml frei0r_pr0file.xml frei0r_primaries.xml frei0r_rgbparade.xml frei0r_saturat0r.xml frei0r_scale0tilt.xml frei0r_scanline0r.xml frei0r_select0r.xml frei0r_sharpness.xml frei0r_sobel.xml frei0r_sopsat.xml frei0r_squareblur.xml frei0r_tehroxx0r.xml frei0r_three_point_balance.xml frei0r_threelay0r.xml frei0r_threshold0r.xml frei0r_timeout.xml frei0r_tint0r.xml frei0r_twolay0r.xml frei0r_vectorscope.xml frei0r_vertigo.xml frei0r_vignette.xml frei0r_facebl0r.xml frei0r_facedetect.xml fade_from_black.xml fade_to_black.xml gain.xml lift_gamma_gain.xml movit_blur.xml movit_deconvolution_sharpen.xml movit_diffusion.xml movit_glow.xml movit_lift_gamma_gain.xml movit_mirror.xml movit_opacity.xml movit_rect.xml movit_saturation.xml movit_unsharp_mask.xml movit_vignette.xml movit_white_balance.xml qtblend.xml rotoscoping.xml speed.xml swapchannels.xml tcolor.xml -vignette.xml tracker.xml - +vignette.xml +vidstab.xml DESTINATION ${DATA_INSTALL_DIR}/kdenlive/effects) add_subdirectory(update) add_subdirectory(avfilter) diff --git a/data/effects/vidstab.xml b/data/effects/vidstab.xml new file mode 100644 index 000000000..823de46be --- /dev/null +++ b/data/effects/vidstab.xml @@ -0,0 +1,64 @@ + + + Stabilize + Adjust audio volume with keyframes + Dan Dennedy + + Accuracy + Accuracy of Shakiness detection + + + Shakiness + How shaky is the Video + + + Stepsize + Stepsize of Detection process minimum around + + + Min. contrast + Below this Contrast Field is discarded + + + Smoothing + Number of frames for lowpass filtering + + + Max shift + Max number of pixels to shift (-1 = no limit) + + + Max angle + Max angle to rotate (in rad) + + + Crop + Disabled = keep border, enabled = black background + + + Zoom + Additional zoom during transform + + + Optimal Zoom + Automatically determine optimal zoom. 1 - static zoom, 2 - adaptive zoom + + + Optimal Zoom Speed + Zoom per frame (used when optimal zoom = 2) + + + Sharpen + Sharpen transformed image + + + Show fields + 0 = draw nothing 1 or 2 = show fields and transforms + + + Tripod + Reference frame + + + + diff --git a/src/assets/view/assetparameterview.cpp b/src/assets/view/assetparameterview.cpp index 409816c7e..19221b4fc 100644 --- a/src/assets/view/assetparameterview.cpp +++ b/src/assets/view/assetparameterview.cpp @@ -1,352 +1,352 @@ /*************************************************************************** * 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); } 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::valuesChanged, this, &AssetParameterView::commitMultipleChanges); 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); // Unselect preset if any QAction *ac = m_presetGroup->checkedAction(); if (ac) { ac->setChecked(false);; } } 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) { + if (storeUndo && m_model->getOwnerId().second != -1) { pCore->pushUndo(command); } else { command->redo(); delete command; } } void AssetParameterView::commitMultipleChanges(const QList indexes, const QStringList &values, 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 AssetMultiCommand(m_model, indexes, values); 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; } int max; if (!bottomRight.isValid()) { max = (int)m_widgets.size() - 1; } else { max = 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/project/clipstabilize.cpp b/src/project/clipstabilize.cpp index f37c348c8..dbf730fa0 100644 --- a/src/project/clipstabilize.cpp +++ b/src/project/clipstabilize.cpp @@ -1,234 +1,155 @@ /*************************************************************************** * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * * Copyright (C) 2011 by Marco Gittler (marco@gitma.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 "clipstabilize.h" #include "bin/projectclip.h" #include "bin/projectitemmodel.h" #include "core.h" #include "widgets/doublewidget.h" #include "widgets/positionwidget.h" +#include "assets/view/assetparameterview.hpp" +#include "assets/model/assetparametermodel.hpp" +#include "effects/effectsrepository.hpp" #include "kdenlivesettings.h" #include #include #include ClipStabilize::ClipStabilize(const std::vector &binIds, QString filterName, int out, QWidget *parent) : QDialog(parent) , m_filtername(std::move(filterName)) , m_binIds(binIds) , m_vbox(nullptr) + , m_assetModel(nullptr) { setFont(QFontDatabase::systemFont(QFontDatabase::SmallestReadableFont)); setupUi(this); setWindowTitle(i18n("Stabilize Clip")); auto_add->setText(i18np("Add clip to project", "Add clips to project", m_binIds.size())); auto_add->setChecked(KdenliveSettings::add_new_clip()); // QString stylesheet = EffectStackView2::getStyleSheet(); // setStyleSheet(stylesheet); Q_ASSERT(binIds.size() > 0); auto firstBinClip = pCore->projectItemModel()->getClipByBinID(m_binIds.front()); auto firstUrl = firstBinClip->url(); if (m_binIds.size() == 1) { QString newFile = firstUrl; newFile.append(QStringLiteral(".mlt")); dest_url->setMode(KFile::File); dest_url->setUrl(QUrl(newFile)); } else { label_dest->setText(i18n("Destination folder")); dest_url->setMode(KFile::Directory | KFile::ExistingOnly); dest_url->setUrl(QUrl(firstUrl).adjusted(QUrl::RemoveFilename)); } - + m_vbox = new QVBoxLayout(optionsbox); if (m_filtername == QLatin1String("vidstab") || m_filtername == QLatin1String("videostab2")) { - m_fixedParams[QStringLiteral("algo")] = QStringLiteral("1"); - m_fixedParams[QStringLiteral("relative")] = QStringLiteral("1"); - fillParameters( - QStringList() << QStringLiteral("accuracy,type,int,value,8,min,1,max,10,tooltip,Accuracy of Shakiness detection") - << QStringLiteral("shakiness,type,int,value,4,min,1,max,10,tooltip,How shaky is the Video") - << QStringLiteral("stepsize,type,int,value,6,min,0,max,100,tooltip,Stepsize of Detection process minimum around") - << QStringLiteral("mincontrast,type,double,value,0.3,min,0,max,1,factor,1,decimals,2,tooltip,Below this Contrast Field is discarded") - << QStringLiteral("smoothing,type,int,value,10,min,0,max,100,tooltip,number of frames for lowpass filtering") - << QStringLiteral("maxshift,type,int,value,-1,min,-1,max,1000,tooltip,max number of pixels to shift") - << QStringLiteral("maxangle,type,double,value,-1,min,-1,max,3.14,decimals,2,tooltip,max angle to rotate (in rad)") - << QStringLiteral("crop,type,bool,value,0,min,0,max,1,tooltip,0 = keep border 1 = black background") - << QStringLiteral("zoom,type,int,value,0,min,-500,max,500,tooltip,additional zoom during transform") - << QStringLiteral("optzoom,type,bool,value,1,min,0,max,1,tooltip,use optimal zoom (calculated from transforms)") - << QStringLiteral("sharpen,type,double,value,0.8,min,0,max,1,decimals,1,tooltip,sharpen transformed image") - << QStringLiteral("tripod,type,position,value,0,min,0,max,100000,tooltip,reference frame")); - - } else if (m_filtername == QLatin1String("videostab")) { - fillParameters(QStringList(QStringLiteral("shutterangle,type,int,value,0,min,0,max,180,tooltip,Angle that Images could be maximum rotated"))); + AssetParameterView *view = new AssetParameterView(this); + std::unique_ptr asset = EffectsRepository::get()->getEffect(m_filtername); + auto prop = std::make_unique(asset->get_properties()); + QDomElement xml = EffectsRepository::get()->getXml(m_filtername); + m_assetModel.reset(new AssetParameterModel(std::move(prop), xml, m_filtername, {ObjectType::NoItem, -1})); + view->setModel(m_assetModel, QSize(1920, 1080)); + m_vbox->addWidget(view); } connect(buttonBox->button(QDialogButtonBox::Ok), &QPushButton::clicked, this, &ClipStabilize::slotValidate); - - m_vbox = new QVBoxLayout(optionsbox); - QHashIterator> hi(m_ui_params); - m_tc.setFormat(KdenliveSettings::project_fps()); - while (hi.hasNext()) { - hi.next(); - QHash val = hi.value(); - if (val[QStringLiteral("type")] == QLatin1String("int") || val[QStringLiteral("type")] == QLatin1String("double")) { - DoubleWidget *dbl = new DoubleWidget(hi.key() /*name*/, val[QStringLiteral("value")].toDouble(), val[QStringLiteral("min")].toDouble(), - val[QStringLiteral("max")].toDouble(), val[QStringLiteral("value")].toDouble(), 1, - /*default*/ - QString(), /*comment*/ - 0 /*id*/, QString(), /*suffix*/ - val[QStringLiteral("decimals")] != QString() ? val[QStringLiteral("decimals")].toInt() : 0, this); - dbl->setObjectName(hi.key()); - dbl->setToolTip(val[QStringLiteral("tooltip")]); - connect(dbl, &DoubleWidget::valueChanged, this, &ClipStabilize::slotUpdateParams); - m_vbox->addWidget(dbl); - } else if (val[QStringLiteral("type")] == QLatin1String("bool")) { - auto *ch = new QCheckBox(hi.key(), this); - ch->setCheckState(val[QStringLiteral("value")] == QLatin1String("0") ? Qt::Unchecked : Qt::Checked); - ch->setObjectName(hi.key()); - connect(ch, &QCheckBox::stateChanged, this, &ClipStabilize::slotUpdateParams); - ch->setToolTip(val[QStringLiteral("tooltip")]); - m_vbox->addWidget(ch); - } else if (val[QStringLiteral("type")] == QLatin1String("position")) { - PositionWidget *posedit = new PositionWidget(hi.key(), 0, 0, out, m_tc, QString(), this); - posedit->setToolTip(val[QStringLiteral("tooltip")]); - posedit->setObjectName(hi.key()); - m_vbox->addWidget(posedit); - connect(posedit, &PositionWidget::valueChanged, this, &ClipStabilize::slotUpdateParams); - } - } adjustSize(); } ClipStabilize::~ClipStabilize() { /*if (m_stabilizeProcess.state() != QProcess::NotRunning) { m_stabilizeProcess.close(); }*/ KdenliveSettings::setAdd_new_clip(auto_add->isChecked()); } std::unordered_map ClipStabilize::filterParams() const { + QVector> result = m_assetModel->getAllParameters(); std::unordered_map params; + QLocale locale; - for (const auto &it : m_fixedParams) { - params[it.first] = it.second; - } - - QHashIterator> it(m_ui_params); - while (it.hasNext()) { - it.next(); - params[it.key()] = it.value().value(QStringLiteral("value")); + for (const auto &it : result) { + if (it.second.type() == QVariant::Double) { + params[it.first] = locale.toString(it.second.toDouble()); + } else { + params[it.first] = it.second.toString(); + } } return params; } QString ClipStabilize::filterName() const { return m_filtername; } QString ClipStabilize::destination() const { QString path = dest_url->url().toLocalFile(); if (m_binIds.size() > 1 && !path.endsWith(QDir::separator())) { path.append(QDir::separator()); } return path; } QString ClipStabilize::desc() const { return i18n("Stabilize clip"); } -void ClipStabilize::slotUpdateParams() -{ - for (int i = 0; i < m_vbox->count(); ++i) { - QWidget *w = m_vbox->itemAt(i)->widget(); - QString name = w->objectName(); - if (!name.isEmpty() && m_ui_params.contains(name)) { - if (m_ui_params[name][QStringLiteral("type")] == QLatin1String("int") || m_ui_params[name][QStringLiteral("type")] == QLatin1String("double")) { - auto *dbl = static_cast(w); - m_ui_params[name][QStringLiteral("value")] = QString::number((double)(dbl->getValue())); - } else if (m_ui_params[name][QStringLiteral("type")] == QLatin1String("bool")) { - auto *ch = (QCheckBox *)w; - m_ui_params[name][QStringLiteral("value")] = ch->checkState() == Qt::Checked ? QStringLiteral("1") : QStringLiteral("0"); - } else if (m_ui_params[name][QStringLiteral("type")] == QLatin1String("position")) { - auto *pos = (PositionWidget *)w; - m_ui_params[name][QStringLiteral("value")] = QString::number(pos->getPosition()); - } - } - } -} - bool ClipStabilize::autoAddClip() const { return auto_add->isChecked(); } -void ClipStabilize::fillParameters(QStringList lst) -{ - - m_ui_params.clear(); - while (!lst.isEmpty()) { - QString vallist = lst.takeFirst(); - QStringList cont = vallist.split(QLatin1Char(',')); - QString name = cont.takeFirst(); - while (!cont.isEmpty()) { - QString valname = cont.takeFirst(); - QString val; - if (!cont.isEmpty()) { - val = cont.takeFirst(); - } - m_ui_params[name][valname] = val; - } - } -} - void ClipStabilize::slotValidate() { if (m_binIds.size() == 1) { if (QFile::exists(dest_url->url().toLocalFile())) { if (KMessageBox::questionYesNo(this, i18n("File %1 already exists.\nDo you want to overwrite it?", dest_url->url().toLocalFile())) == KMessageBox::No) { return; } } } else { QDir folder(dest_url->url().toLocalFile()); QStringList existingFiles; for (const QString &binId : m_binIds) { auto binClip = pCore->projectItemModel()->getClipByBinID(binId); auto url = binClip->url(); if (folder.exists(url + QStringLiteral(".mlt"))) { existingFiles.append(folder.absoluteFilePath(url + QStringLiteral(".mlt"))); } } if (!existingFiles.isEmpty()) { if (KMessageBox::warningContinueCancelList(this, i18n("The stabilize job will overwrite the following files:"), existingFiles) == KMessageBox::Cancel) { return; } } } accept(); } diff --git a/src/project/clipstabilize.h b/src/project/clipstabilize.h index a4e5331e7..8bcd0b92d 100644 --- a/src/project/clipstabilize.h +++ b/src/project/clipstabilize.h @@ -1,65 +1,64 @@ /*************************************************************************** * Copyright (C) 2008 by Jean-Baptiste Mardelle (jb@kdenlive.org) * * Copyright (C) 2011 by Marco Gittler (marco@gitma.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 CLIPSTABILIZE_H #define CLIPSTABILIZE_H #include "definitions.h" #include "timecode.h" #include "ui_clipstabilize_ui.h" #include #include +class AssetParameterModel; + class ClipStabilize : public QDialog, public Ui::ClipStabilize_UI { Q_OBJECT public: explicit ClipStabilize(const std::vector &binIds, QString filterName, int out, QWidget *parent = nullptr); ~ClipStabilize() override; /** @brief Should the generated clip be added to current project. */ bool autoAddClip() const; /** @brief Return the filter parameters, filter name as value of "filter" entry. */ std::unordered_map filterParams() const; /** @brief Return the destination file or folder. */ QString destination() const; /** @brief Return the job description. */ QString desc() const; /* Return the name of the actual mlt filter used */ QString filterName() const; private slots: - void slotUpdateParams(); void slotValidate(); private: QString m_filtername; std::vector m_binIds; - QHash> m_ui_params; QVBoxLayout *m_vbox; - void fillParameters(QStringList); - std::unordered_map m_fixedParams; Timecode m_tc; + std::shared_ptrm_assetModel; signals: void addClip(const QUrl &url); }; #endif