diff --git a/data/effects/lift_gamma_gain.xml b/data/effects/lift_gamma_gain.xml index 6a56b5034..ef6924706 100644 --- a/data/effects/lift_gamma_gain.xml +++ b/data/effects/lift_gamma_gain.xml @@ -1,32 +1,32 @@ Lift/gamma/gain Brian Matherly Lift: Red Lift: Green Lift: Blue - + Gamma: Red - + Gamma: Green - + Gamma: Blue - + Gain: Red - + Gain: Green - + Gain: Blue diff --git a/src/assets/model/assetcommand.cpp b/src/assets/model/assetcommand.cpp index 4328a80c4..983a100e9 100644 --- a/src/assets/model/assetcommand.cpp +++ b/src/assets/model/assetcommand.cpp @@ -1,151 +1,212 @@ /*************************************************************************** * Copyright (C) 2017 by by Jean-Baptiste Mardelle * * This file is part of Kdenlive. See www.kdenlive.org. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) version 3 or any later version accepted by the * * membership of KDE e.V. (or its successor approved by the membership * * of KDE e.V.), which shall act as a proxy defined in Section 14 of * * version 3 of the license. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * ***************************************************************************/ #include "assetcommand.hpp" #include "assets/keyframes/model/keyframemodellist.hpp" #include "effects/effectsrepository.hpp" #include "transitions/transitionsrepository.hpp" #include #include AssetCommand::AssetCommand(const std::shared_ptr &model, const QModelIndex &index, QString value, QUndoCommand *parent) : QUndoCommand(parent) , m_model(model) , m_index(index) , m_value(std::move(value)) , m_updateView(false) , m_stamp(QTime::currentTime()) { QLocale locale; m_name = m_model->data(index, AssetParameterModel::NameRole).toString(); const QString id = model->getAssetId(); if (EffectsRepository::get()->exists(id)) { setText(i18n("Edit %1", EffectsRepository::get()->getName(id))); } else if (TransitionsRepository::get()->exists(id)) { setText(i18n("Edit %1", TransitionsRepository::get()->getName(id))); } QVariant previousVal = m_model->data(index, AssetParameterModel::ValueRole); m_oldValue = previousVal.type() == QVariant::Double ? locale.toString(previousVal.toDouble()) : previousVal.toString(); } void AssetCommand::undo() { m_model->setParameter(m_name, m_oldValue, true, m_index); } // virtual void AssetCommand::redo() { m_model->setParameter(m_name, m_value, m_updateView, m_index); m_updateView = true; } // virtual int AssetCommand::id() const { return 1; } // virtual bool AssetCommand::mergeWith(const QUndoCommand *other) { if (other->id() != id() || static_cast(other)->m_index != m_index || m_stamp.msecsTo(static_cast(other)->m_stamp) > 3000) { return false; } m_value = static_cast(other)->m_value; m_stamp = static_cast(other)->m_stamp; return true; } +AssetMultiCommand::AssetMultiCommand(const std::shared_ptr &model, const QList indexes, const QStringList values, QUndoCommand *parent) + : QUndoCommand(parent) + , m_model(model) + , m_indexes(indexes) + , m_values(values) + , m_updateView(false) + , m_stamp(QTime::currentTime()) +{ + QLocale locale; + qDebug()<<"CREATING MULTIPLE COMMAND!!!\nVALUES: "<data(indexes.first(), AssetParameterModel::NameRole).toString(); + const QString id = model->getAssetId(); + if (EffectsRepository::get()->exists(id)) { + setText(i18n("Edit %1", EffectsRepository::get()->getName(id))); + } else if (TransitionsRepository::get()->exists(id)) { + setText(i18n("Edit %1", TransitionsRepository::get()->getName(id))); + } + for (QModelIndex ix : m_indexes) { + QVariant previousVal = m_model->data(ix, AssetParameterModel::ValueRole); + m_oldValues << (previousVal.type() == QVariant::Double ? locale.toString(previousVal.toDouble()) : previousVal.toString()); + } +} + +void AssetMultiCommand::undo() +{ + int indx = 0; + int max = m_indexes.size() - 1; + for (const QModelIndex &ix : m_indexes) { + m_model->setParameter(m_model->data(ix, AssetParameterModel::NameRole).toString(), m_oldValues.at(indx), indx == max, ix); + indx++; + } +} +// virtual +void AssetMultiCommand::redo() +{ + int indx = 0; + int max = m_indexes.size() - 1; + for (const QModelIndex &ix : m_indexes) { + m_model->setParameter(m_model->data(ix, AssetParameterModel::NameRole).toString(), m_values.at(indx), m_updateView && indx == max, ix); + indx++; + } + m_updateView = true; +} + +// virtual +int AssetMultiCommand::id() const +{ + return 1; +} +// virtual +bool AssetMultiCommand::mergeWith(const QUndoCommand *other) +{ + if (other->id() != id() || static_cast(other)->m_indexes != m_indexes || + m_stamp.msecsTo(static_cast(other)->m_stamp) > 3000) { + return false; + } + m_values = static_cast(other)->m_values; + m_stamp = static_cast(other)->m_stamp; + return true; +} + AssetKeyframeCommand::AssetKeyframeCommand(const std::shared_ptr &model, const QModelIndex &index, QVariant value, GenTime pos, QUndoCommand *parent) : QUndoCommand(parent) , m_model(model) , m_index(index) , m_value(std::move(value)) , m_pos(pos) , m_updateView(false) , m_stamp(QTime::currentTime()) { const QString id = model->getAssetId(); if (EffectsRepository::get()->exists(id)) { setText(i18n("Edit %1 keyframe", EffectsRepository::get()->getName(id))); } else if (TransitionsRepository::get()->exists(id)) { setText(i18n("Edit %1 keyframe", TransitionsRepository::get()->getName(id))); } m_oldValue = m_model->getKeyframeModel()->getKeyModel(m_index)->getInterpolatedValue(m_pos); } void AssetKeyframeCommand::undo() { m_model->getKeyframeModel()->getKeyModel(m_index)->directUpdateKeyframe(m_pos, m_oldValue); } // virtual void AssetKeyframeCommand::redo() { m_model->getKeyframeModel()->getKeyModel(m_index)->directUpdateKeyframe(m_pos, m_value); m_updateView = true; } // virtual int AssetKeyframeCommand::id() const { return 2; } // virtual bool AssetKeyframeCommand::mergeWith(const QUndoCommand *other) { if (other->id() != id() || static_cast(other)->m_index != m_index || m_stamp.msecsTo(static_cast(other)->m_stamp) > 1000) { return false; } m_value = static_cast(other)->m_value; m_stamp = static_cast(other)->m_stamp; return true; } AssetUpdateCommand::AssetUpdateCommand(const std::shared_ptr &model, QVector> parameters, QUndoCommand *parent) : QUndoCommand(parent) , m_model(model) , m_value(std::move(parameters)) { const QString id = model->getAssetId(); if (EffectsRepository::get()->exists(id)) { setText(i18n("Update %1", EffectsRepository::get()->getName(id))); } else if (TransitionsRepository::get()->exists(id)) { setText(i18n("Update %1", TransitionsRepository::get()->getName(id))); } m_oldValue = m_model->getAllParameters(); } void AssetUpdateCommand::undo() { m_model->setParameters(m_oldValue); } // virtual void AssetUpdateCommand::redo() { m_model->setParameters(m_value); } // virtual int AssetUpdateCommand::id() const { return 3; } diff --git a/src/assets/model/assetcommand.hpp b/src/assets/model/assetcommand.hpp index f24b62538..4d8fec57f 100644 --- a/src/assets/model/assetcommand.hpp +++ b/src/assets/model/assetcommand.hpp @@ -1,82 +1,101 @@ /*************************************************************************** * Copyright (C) 2017 by Jean-Baptiste Mardelle * * This file is part of Kdenlive. See www.kdenlive.org. * * * * This program is free software; you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation; either version 2 of the License, or * * (at your option) version 3 or any later version accepted by the * * membership of KDE e.V. (or its successor approved by the membership * * of KDE e.V.), which shall act as a proxy defined in Section 14 of * * version 3 of the license. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * ***************************************************************************/ #ifndef ASSETCOMMAND_H #define ASSETCOMMAND_H #include "assetparametermodel.hpp" #include #include #include class AssetCommand : public QUndoCommand { public: AssetCommand(const std::shared_ptr &model, const QModelIndex &index, QString value, QUndoCommand *parent = nullptr); void undo() override; void redo() override; int id() const override; bool mergeWith(const QUndoCommand *other) override; private: std::shared_ptr m_model; QPersistentModelIndex m_index; QString m_value; QString m_name; QString m_oldValue; bool m_updateView; QTime m_stamp; }; +class AssetMultiCommand : public QUndoCommand +{ +public: + AssetMultiCommand(const std::shared_ptr &model, const QList indexes, const QStringList values, QUndoCommand *parent = nullptr); + void undo() override; + void redo() override; + int id() const override; + bool mergeWith(const QUndoCommand *other) override; + +private: + std::shared_ptr m_model; + QList m_indexes; + QStringList m_values; + QString m_name; + QStringList m_oldValues; + bool m_updateView; + QTime m_stamp; +}; + class AssetKeyframeCommand : public QUndoCommand { public: AssetKeyframeCommand(const std::shared_ptr &model, const QModelIndex &index, QVariant value, GenTime pos, QUndoCommand *parent = nullptr); void undo() override; void redo() override; int id() const override; bool mergeWith(const QUndoCommand *other) override; private: std::shared_ptr m_model; QPersistentModelIndex m_index; QVariant m_value; QVariant m_oldValue; GenTime m_pos; bool m_updateView; QTime m_stamp; }; class AssetUpdateCommand : public QUndoCommand { public: AssetUpdateCommand(const std::shared_ptr &model, QVector> parameters, QUndoCommand *parent = nullptr); void undo() override; void redo() override; int id() const override; private: std::shared_ptr m_model; QVector> m_value; QVector> m_oldValue; }; #endif diff --git a/src/assets/view/assetparameterview.cpp b/src/assets/view/assetparameterview.cpp index 679c246f9..330cdba9e 100644 --- a/src/assets/view/assetparameterview.cpp +++ b/src/assets/view/assetparameterview.cpp @@ -1,337 +1,350 @@ /*************************************************************************** * 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); /*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::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/assets/view/assetparameterview.hpp b/src/assets/view/assetparameterview.hpp index 1a3e4fb55..68a7627bc 100644 --- a/src/assets/view/assetparameterview.hpp +++ b/src/assets/view/assetparameterview.hpp @@ -1,112 +1,113 @@ /*************************************************************************** * 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 . * ***************************************************************************/ #ifndef ASSETPARAMETERVIEW_H #define ASSETPARAMETERVIEW_H #include "definitions.h" #include #include #include #include #include /* @brief This class is the view for a list of parameters. */ class QVBoxLayout; class QMenu; class QActionGroup; class AbstractParamWidget; class AssetParameterModel; class KeyframeWidget; class AssetParameterView : public QWidget { Q_OBJECT public: AssetParameterView(QWidget *parent = nullptr); /** Sets the model to be displayed by current view */ virtual void setModel(const std::shared_ptr &model, QSize frameSize, bool addSpacer = false); /** Set the widget to display no model (this yield ownership on the smart-ptr)*/ void unsetModel(); /** Returns the preferred widget height */ int contentHeight() const; /** Returns the type of monitor overlay required by this effect */ MonitorSceneType needsMonitorEffectScene() const; /** Returns true is the effect can use keyframes */ bool keyframesAllowed() const; /** Returns true is the keyframes should be hidden on first opening*/ bool modelHideKeyframes() const; /** Returns the preset menu to be embedded in toolbars */ QMenu *presetMenu(); public slots: void slotRefresh(); void toggleKeyframes(bool enable); /** Reset all parameter values to default */ void resetValues(); /** Save all parameters to a preset */ void slotSavePreset(QString presetName = QString()); /** Save all parameters to a preset */ void slotLoadPreset(); void slotUpdatePreset(); void slotDeletePreset(); protected: /** @brief This is a handler for the dataChanged slot of the model. It basically instructs the widgets in the given range to be refreshed */ void refresh(const QModelIndex &topLeft, const QModelIndex &bottomRight, const QVector &roles); QVBoxLayout *m_lay; /** @brief Protect from concurrent operations **/ QMutex m_lock; std::shared_ptr m_model; std::vector m_widgets; KeyframeWidget *m_mainKeyframeWidget{nullptr}; QMenu *m_presetMenu; std::shared_ptr m_presetGroup; private slots: /** @brief Apply a change of parameter sent by the view @param index is the index corresponding to the modified param @param value is the new value of the parameter @param storeUndo: if true, an undo object is created */ void commitChanges(const QModelIndex &index, const QString &value, bool storeUndo); + void commitMultipleChanges(const QList indexes, const QStringList &values, bool storeUndo); QVector> getDefaultValues() const; signals: void seekToPos(int); void initKeyframeView(bool active); /** @brief clear and refill the effect presets */ void updatePresets(const QString &presetName = QString()); }; #endif diff --git a/src/assets/view/widgets/abstractparamwidget.hpp b/src/assets/view/widgets/abstractparamwidget.hpp index 3ac5b2fe6..8f02c6e1f 100644 --- a/src/assets/view/widgets/abstractparamwidget.hpp +++ b/src/assets/view/widgets/abstractparamwidget.hpp @@ -1,83 +1,84 @@ /*************************************************************************** * Copyright (C) 2016 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 . * ***************************************************************************/ #ifndef ABSTRACTPARAMWIDGET_H #define ABSTRACTPARAMWIDGET_H #include #include #include #include /** @brief Base class of all the widgets representing a parameter of an asset (effect or transition) */ class AssetParameterModel; class AbstractParamWidget : public QWidget { Q_OBJECT public: AbstractParamWidget() = delete; AbstractParamWidget(std::shared_ptr model, QModelIndex index, QWidget *parent); ~AbstractParamWidget() override = default; /** @brief Factory method to construct a parameter widget. @param model Parameter model this parameter belongs to @param index Index of the parameter in the given model @param parent parent widget */ static AbstractParamWidget *construct(const std::shared_ptr &model, QModelIndex index, QSize frameSize, QWidget *parent); signals: /** @brief Signal sent when the parameters hold by the widgets are modified The index corresponds which parameter is changed The string is the new value The bool allows to decide whether an undo object should be created */ void valueChanged(QModelIndex, QString, bool); + void valuesChanged(const QList , const QStringList&, bool); /* @brief Signal sent when the filter needs to be deactivated or reactivated. This happens for example when the user has to pick a color. */ void disableCurrentFilter(bool); void seekToPos(int); public slots: /** @brief Toggle the comments on or off */ virtual void slotShowComment(bool) { qDebug() << "DEBUG: show_comment not correctly overridden"; } /** @brief refresh the properties to reflect changes in the model */ virtual void slotRefresh() = 0; /** @brief initialize qml keyframe view after creating it */ virtual void slotInitMonitor(bool /*active*/) {} protected: std::shared_ptr m_model; QPersistentModelIndex m_index; }; #endif diff --git a/src/assets/view/widgets/colorwheel.cpp b/src/assets/view/widgets/colorwheel.cpp index 7560c405d..b6338ee80 100644 --- a/src/assets/view/widgets/colorwheel.cpp +++ b/src/assets/view/widgets/colorwheel.cpp @@ -1,341 +1,342 @@ /* * Copyright (c) 2013 Meltytech, LLC * Author: Dan Dennedy * Some ideas came from Qt-Plus: https://github.com/liuyanghejerry/Qt-Plus * and Steinar Gunderson's Movit demo app. * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * 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 "colorwheel.h" #include #include NegQColor NegQColor::fromHsvF(qreal h, qreal s, qreal l, qreal a) { NegQColor color; color.qcolor = QColor::fromHsvF(h, s, l < 0 ? -l : l, a); color.sign_r = l < 0 ? -1 : 1; color.sign_g = l < 0 ? -1 : 1; color.sign_b = l < 0 ? -1 : 1; return color; } NegQColor NegQColor::fromRgbF(qreal r, qreal g, qreal b, qreal a) { NegQColor color; color.qcolor = QColor::fromRgbF(r < 0 ? -r : r, g < 0 ? -g : g, b < 0 ? -b : b, a); color.sign_r = r < 0 ? -1 : 1; color.sign_g = g < 0 ? -1 : 1; color.sign_b = b < 0 ? -1 : 1; return color; } qreal NegQColor::redF() { return qcolor.redF() * sign_r; } qreal NegQColor::greenF() { return qcolor.greenF() * sign_g; } qreal NegQColor::blueF() { return qcolor.blueF() * sign_b; } qreal NegQColor::valueF() { return qcolor.valueF() * sign_g; } int NegQColor::hue() { return qcolor.hue(); } qreal NegQColor::hueF() { return qcolor.hueF(); } qreal NegQColor::saturationF() { return qcolor.saturationF(); } ColorWheel::ColorWheel(QString id, QString name, NegQColor color, QWidget *parent) : QWidget(parent) , m_id(std::move(id)) , m_isMouseDown(false) , m_margin(5) , m_color(std::move(color)) , m_isInWheel(false) , m_isInSquare(false) , m_name(std::move(name)) { QFontInfo info(font()); m_unitSize = info.pixelSize(); m_initialSize = QSize(m_unitSize * 11.5, m_unitSize * 11); m_sliderWidth = m_unitSize * 1.5; resize(m_initialSize); setMinimumSize(100, 100); setMaximumSize(m_initialSize); setCursor(Qt::CrossCursor); } void ColorWheel::setFactorDefaultZero(qreal factor, qreal defvalue, qreal zero) { m_sizeFactor = factor; m_defaultValue = defvalue; m_zeroShift = zero; } NegQColor ColorWheel::color() const { return m_color; } void ColorWheel::setColor(const NegQColor &color) { m_color = color; + update(); } int ColorWheel::wheelSize() const { return qMin(width() - m_sliderWidth, height() - m_unitSize); } NegQColor ColorWheel::colorForPoint(const QPoint &point) { if (!m_image.valid(point)) { return NegQColor(); } if (m_isInWheel) { qreal w = wheelSize(); qreal xf = qreal(point.x()) / w; qreal yf = 1.0 - qreal(point.y()) / w; qreal xp = 2.0 * xf - 1.0; qreal yp = 2.0 * yf - 1.0; qreal rad = qMin(hypot(xp, yp), 1.0); qreal theta = qAtan2(yp, xp); theta -= 105.0 / 360.0 * 2.0 * M_PI; if (theta < 0.0) { theta += 2.0 * M_PI; } qreal hue = (theta * 180.0 / M_PI) / 360.0; return NegQColor::fromHsvF(hue, rad, m_color.valueF()); } if (m_isInSquare) { qreal value = 1.0 - qreal(point.y() - m_margin) / (wheelSize() - m_margin * 2); if (!qFuzzyCompare(m_zeroShift, 0.)) { value = value - m_zeroShift; } return NegQColor::fromHsvF(m_color.hueF(), m_color.saturationF(), value); } return {}; } QSize ColorWheel::sizeHint() const { return {width(), height()}; } QSize ColorWheel::minimumSizeHint() const { return {100, 100}; } void ColorWheel::mousePressEvent(QMouseEvent *event) { m_lastPoint = event->pos(); if (m_wheelRegion.contains(m_lastPoint)) { m_isInWheel = true; m_isInSquare = false; if (event->button() == Qt::LeftButton) { changeColor(colorForPoint(m_lastPoint)); } else { // reset to default on middle/right button qreal r = m_color.redF(); qreal b = m_color.blueF(); qreal g = m_color.greenF(); qreal max = qMax(r, b); max = qMax(max, g); changeColor(NegQColor::fromRgbF(max, max, max)); } } else if (m_sliderRegion.contains(m_lastPoint)) { m_isInWheel = false; m_isInSquare = true; if (event->button() == Qt::LeftButton) { changeColor(colorForPoint(m_lastPoint)); } else { NegQColor c; c = NegQColor::fromHsvF(m_color.hueF(), m_color.saturationF(), m_defaultValue / m_sizeFactor); changeColor(c); } } m_isMouseDown = true; } void ColorWheel::mouseMoveEvent(QMouseEvent *event) { m_lastPoint = event->pos(); if (!m_isMouseDown) { return; } if (m_wheelRegion.contains(m_lastPoint) && m_isInWheel) { const NegQColor color = colorForPoint(m_lastPoint); changeColor(color); } else if (m_sliderRegion.contains(m_lastPoint) && m_isInSquare) { const NegQColor color = colorForPoint(m_lastPoint); changeColor(color); } } void ColorWheel::mouseReleaseEvent(QMouseEvent *event) { Q_UNUSED(event) m_isMouseDown = false; m_isInWheel = false; m_isInSquare = false; } void ColorWheel::resizeEvent(QResizeEvent *event) { m_image = QImage(event->size(), QImage::Format_ARGB32_Premultiplied); m_image.fill(palette().background().color().rgb()); drawWheel(); drawSlider(); update(); } QString ColorWheel::getParamValues() { return QString::number(m_color.redF() * m_sizeFactor, 'g', 2) + QLatin1Char(',') + QString::number(m_color.greenF() * m_sizeFactor, 'g', 2) + QLatin1Char(',') + QString::number(m_color.blueF() * m_sizeFactor, 'g', 2); } void ColorWheel::paintEvent(QPaintEvent *event) { Q_UNUSED(event) QPainter painter(this); // QStyleOption opt; // opt.init(this); painter.setRenderHint(QPainter::Antialiasing); painter.drawImage(0, 0, m_image); // painter.drawRect(0, 0, width(), height()); painter.drawText(m_margin, wheelSize() + m_unitSize - m_margin, m_name + QLatin1Char(' ') + getParamValues()); drawWheelDot(painter); drawSliderBar(painter); // style()->drawPrimitive(QStyle::PE_Widget, &opt, &painter, this); } void ColorWheel::drawWheel() { int r = wheelSize(); QPainter painter(&m_image); painter.setRenderHint(QPainter::Antialiasing); m_image.fill(0); // transparent QConicalGradient conicalGradient; conicalGradient.setColorAt(0.0, Qt::red); conicalGradient.setColorAt(60.0 / 360.0, Qt::yellow); conicalGradient.setColorAt(135.0 / 360.0, Qt::green); conicalGradient.setColorAt(180.0 / 360.0, Qt::cyan); conicalGradient.setColorAt(240.0 / 360.0, Qt::blue); conicalGradient.setColorAt(315.0 / 360.0, Qt::magenta); conicalGradient.setColorAt(1.0, Qt::red); QRadialGradient radialGradient(0.0, 0.0, r / 2); radialGradient.setColorAt(0.0, Qt::white); radialGradient.setColorAt(1.0, Qt::transparent); painter.translate(r / 2, r / 2); painter.rotate(-105); QBrush hueBrush(conicalGradient); painter.setPen(Qt::NoPen); painter.setBrush(hueBrush); painter.drawEllipse(QPoint(0, 0), r / 2 - m_margin, r / 2 - m_margin); QBrush saturationBrush(radialGradient); painter.setBrush(saturationBrush); painter.drawEllipse(QPoint(0, 0), r / 2 - m_margin, r / 2 - m_margin); m_wheelRegion = QRegion(r / 2, r / 2, r - 2 * m_margin, r - 2 * m_margin, QRegion::Ellipse); m_wheelRegion.translate(-(r - 2 * m_margin) / 2, -(r - 2 * m_margin) / 2); } void ColorWheel::drawSlider() { QPainter painter(&m_image); painter.setRenderHint(QPainter::Antialiasing); int ws = wheelSize(); qreal scale = qreal(ws + m_sliderWidth) / maximumWidth(); int w = m_sliderWidth * scale; int h = ws - m_margin * 2; QLinearGradient gradient(0, 0, w, h); gradient.setColorAt(0.0, Qt::white); gradient.setColorAt(1.0, Qt::black); QBrush brush(gradient); painter.setPen(Qt::NoPen); painter.setBrush(brush); painter.translate(ws, m_margin); painter.drawRect(0, 0, w, h); m_sliderRegion = QRegion(ws, m_margin, w, h); } void ColorWheel::drawWheelDot(QPainter &painter) { int r = wheelSize() / 2; QPen pen(Qt::white); pen.setWidth(2); painter.setPen(pen); painter.setBrush(Qt::black); painter.translate(r, r); painter.rotate(360.0 - m_color.hue()); painter.rotate(-105); // r -= margin; painter.drawEllipse(QPointF(m_color.saturationF() * r, 0.0), 4, 4); painter.resetTransform(); } void ColorWheel::drawSliderBar(QPainter &painter) { qreal value = 1.0 - m_color.valueF(); if (m_id == QLatin1String("lift")) { value -= m_zeroShift; } int ws = wheelSize(); qreal scale = qreal(ws + m_sliderWidth) / maximumWidth(); int w = m_sliderWidth * scale; int h = ws - m_margin * 2; QPen pen(Qt::white); pen.setWidth(2); painter.setPen(pen); painter.setBrush(Qt::black); painter.translate(ws, m_margin + value * h); painter.drawRect(0, 0, w, 4); painter.resetTransform(); } void ColorWheel::changeColor(const NegQColor &color) { m_color = color; drawWheel(); drawSlider(); update(); emit colorChange(m_color); } diff --git a/src/assets/view/widgets/lumaliftgainparam.cpp b/src/assets/view/widgets/lumaliftgainparam.cpp index e0637e5a1..26f4c8a10 100644 --- a/src/assets/view/widgets/lumaliftgainparam.cpp +++ b/src/assets/view/widgets/lumaliftgainparam.cpp @@ -1,144 +1,139 @@ /*************************************************************************** * Copyright (C) 2018 by Jean-Baptiste Mardelle (jb@kdenlive.org) * * Some code was borrowed from shotcut * * * * 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 "lumaliftgainparam.hpp" #include "assets/model/assetparametermodel.hpp" #include "colorwheel.h" #include "utils/flowlayout.h" #include static const double LIFT_FACTOR = 2.0; static const double GAMMA_FACTOR = 2.0; static const double GAIN_FACTOR = 4.0; LumaLiftGainParam::LumaLiftGainParam(std::shared_ptr model, QModelIndex index, QWidget *parent) : AbstractParamWidget(std::move(model), index, parent) { auto *flowLayout = new FlowLayout(this, 2, 2, 2); /*QVBoxLayout *layout = new QVBoxLayout(this); layout->setContentsMargins(0, 0, 0, 0); layout->setSpacing(0); */ m_locale.setNumberOptions(QLocale::OmitGroupSeparator); m_lift = new ColorWheel(QStringLiteral("lift"), i18n("Lift"), NegQColor(), this); m_lift->setFactorDefaultZero(LIFT_FACTOR, 0, 0.5); connect(m_lift, &ColorWheel::colorChange, this, &LumaLiftGainParam::liftChanged); m_gamma = new ColorWheel(QStringLiteral("gamma"), i18n("Gamma"), NegQColor(), this); m_gamma->setFactorDefaultZero(GAMMA_FACTOR, 1, 0); connect(m_gamma, &ColorWheel::colorChange, this, &LumaLiftGainParam::gammaChanged); m_gain = new ColorWheel(QStringLiteral("gain"), i18n("Gain"), NegQColor(), this); m_gain->setFactorDefaultZero(GAIN_FACTOR, 1, 0); connect(m_gain, &ColorWheel::colorChange, this, &LumaLiftGainParam::gainChanged); QMap indexes; for (int i = 0; i < m_model->rowCount(); ++i) { QModelIndex local_index = m_model->index(i, 0); QString name = m_model->data(local_index, AssetParameterModel::NameRole).toString(); indexes.insert(name, local_index); } flowLayout->addWidget(m_lift); flowLayout->addWidget(m_gamma); flowLayout->addWidget(m_gain); setLayout(flowLayout); slotRefresh(); connect(this, &LumaLiftGainParam::liftChanged, [this, indexes]() { NegQColor liftColor = m_lift->color(); - emit valueChanged(indexes.value(QStringLiteral("lift_r")), m_locale.toString(liftColor.redF()), true); - emit valueChanged(indexes.value(QStringLiteral("lift_g")), m_locale.toString(liftColor.greenF()), true); - emit valueChanged(indexes.value(QStringLiteral("lift_b")), m_locale.toString(liftColor.blueF()), true); + QList ixes{indexes.value(QStringLiteral("lift_r")),indexes.value(QStringLiteral("lift_g")), indexes.value(QStringLiteral("lift_b"))}; + QStringList values {m_locale.toString(liftColor.redF()), m_locale.toString(liftColor.greenF()), m_locale.toString(liftColor.blueF())}; + emit valuesChanged(ixes, values, true); }); connect(this, &LumaLiftGainParam::gammaChanged, [this, indexes]() { NegQColor gammaColor = m_gamma->color(); - emit valueChanged(indexes.value(QStringLiteral("gamma_r")), m_locale.toString(gammaColor.redF() * GAMMA_FACTOR), true); - emit valueChanged(indexes.value(QStringLiteral("gamma_g")), m_locale.toString(gammaColor.greenF() * GAMMA_FACTOR), true); - emit valueChanged(indexes.value(QStringLiteral("gamma_b")), m_locale.toString(gammaColor.blueF() * GAMMA_FACTOR), true); + QList ixes{indexes.value(QStringLiteral("gamma_r")),indexes.value(QStringLiteral("gamma_g")), indexes.value(QStringLiteral("gamma_b"))}; + QStringList values {m_locale.toString(gammaColor.redF() * GAMMA_FACTOR), m_locale.toString(gammaColor.greenF() * GAMMA_FACTOR), m_locale.toString(gammaColor.blueF() * GAMMA_FACTOR)}; + emit valuesChanged(ixes, values, true); }); connect(this, &LumaLiftGainParam::gainChanged, [this, indexes]() { NegQColor gainColor = m_gain->color(); - emit valueChanged(indexes.value(QStringLiteral("gain_r")), m_locale.toString(gainColor.redF() * GAIN_FACTOR), true); - emit valueChanged(indexes.value(QStringLiteral("gain_g")), m_locale.toString(gainColor.greenF() * GAIN_FACTOR), true); - emit valueChanged(indexes.value(QStringLiteral("gain_b")), m_locale.toString(gainColor.blueF() * GAIN_FACTOR), true); + QList ixes{indexes.value(QStringLiteral("gain_r")),indexes.value(QStringLiteral("gain_g")), indexes.value(QStringLiteral("gain_b"))}; + QStringList values {m_locale.toString(gainColor.redF() * GAIN_FACTOR), m_locale.toString(gainColor.greenF() * GAIN_FACTOR), m_locale.toString(gainColor.blueF() * GAIN_FACTOR)}; + emit valuesChanged(ixes, values, true); }); } void LumaLiftGainParam::updateEffect(QDomElement &effect) { NegQColor lift = m_lift->color(); NegQColor gamma = m_gamma->color(); NegQColor gain = m_gain->color(); QMap values; values.insert(QStringLiteral("lift_r"), lift.redF() * LIFT_FACTOR); values.insert(QStringLiteral("lift_g"), lift.greenF() * LIFT_FACTOR); values.insert(QStringLiteral("lift_b"), lift.blueF() * LIFT_FACTOR); values.insert(QStringLiteral("gamma_r"), gamma.redF() * GAMMA_FACTOR); values.insert(QStringLiteral("gamma_g"), gamma.greenF() * GAMMA_FACTOR); values.insert(QStringLiteral("gamma_b"), gamma.blueF() * GAMMA_FACTOR); values.insert(QStringLiteral("gain_r"), gain.redF() * GAIN_FACTOR); values.insert(QStringLiteral("gain_g"), gain.greenF() * GAIN_FACTOR); values.insert(QStringLiteral("gain_b"), gain.blueF() * GAIN_FACTOR); QDomNodeList namenode = effect.childNodes(); for (int i = 0; i < namenode.count(); ++i) { QDomElement pa = namenode.item(i).toElement(); if (pa.tagName() != QLatin1String("parameter")) { continue; } if (values.contains(pa.attribute(QStringLiteral("name")))) { pa.setAttribute(QStringLiteral("value"), (int)(values.value(pa.attribute(QStringLiteral("name"))) * m_locale.toDouble(pa.attribute(QStringLiteral("factor"), QStringLiteral("1"))))); } } } void LumaLiftGainParam::slotShowComment(bool) {} void LumaLiftGainParam::slotRefresh() { qDebug() << "//REFRESHING WIDGET START--------------__"; QMap values; for (int i = 0; i < m_model->rowCount(); ++i) { QModelIndex local_index = m_model->index(i, 0); QString name = m_model->data(local_index, AssetParameterModel::NameRole).toString(); double val = m_locale.toDouble(m_model->data(local_index, AssetParameterModel::ValueRole).toString()); values.insert(name, val); } NegQColor lift = NegQColor::fromRgbF(values.value(QStringLiteral("lift_r")) / LIFT_FACTOR, values.value(QStringLiteral("lift_g")) / LIFT_FACTOR, values.value(QStringLiteral("lift_b")) / LIFT_FACTOR); NegQColor gamma = NegQColor::fromRgbF(values.value(QStringLiteral("gamma_r")) / GAMMA_FACTOR, values.value(QStringLiteral("gamma_g")) / GAMMA_FACTOR, values.value(QStringLiteral("gamma_b")) / GAMMA_FACTOR); NegQColor gain = NegQColor::fromRgbF(values.value(QStringLiteral("gain_r")) / GAIN_FACTOR, values.value(QStringLiteral("gain_g")) / GAIN_FACTOR, values.value(QStringLiteral("gain_b")) / GAIN_FACTOR); - /*QColor lift = QColor::fromRgbF(values.value(QStringLiteral("lift_r")), values.value(QStringLiteral("lift_g")), values.value(QStringLiteral("lift_b"))); - QColor gamma = QColor::fromRgbF(values.value(QStringLiteral("gamma_r")) / GAMMA_FACTOR, values.value(QStringLiteral("gamma_g")) / GAMMA_FACTOR, - values.value(QStringLiteral("gamma_b")) / GAMMA_FACTOR); - QColor gain = QColor::fromRgbF(values.value(QStringLiteral("gain_r")) / GAIN_FACTOR, values.value(QStringLiteral("gain_g")) / GAIN_FACTOR, - values.value(QStringLiteral("gain_b")) / GAIN_FACTOR);*/ qDebug() << "//REFRESHING WIDGET START 2--------------__"; m_lift->setColor(lift); m_gamma->setColor(gamma); m_gain->setColor(gain); qDebug() << "//REFRESHING WIDGET START DONE--------------__"; }