Warning, /multimedia/kdenlive/src/assets/view/widgets/curves/curveparamwidget.ipp is written in an unsupported language. File is not indexed.

0001 /*
0002  * SPDX-FileCopyrightText: 2016 Nicolas Carion
0003  * SPDX-License-Identifier: GPL-3.0-only OR LicenseRef-KDE-Accepted-GPL
0004  */
0005 
0006 #include "bezier/beziersplineeditor.h"
0007 #include "utils/colortools.h"
0008 #include "cubic/kis_curve_widget.h"
0009 #include "kdenlivesettings.h"
0010 #include "widgets/dragvalue.h"
0011 #include <KLocalizedString>
0012 
0013 /** @brief this label is a pixmap corresponding to a legend of the axis*/
0014 template <typename CurveWidget_t> class ValueLabel : public QLabel
0015 {
0016 public:
0017     /** @brief Creates the widget
0018        @param isVert This parameter is true if the widget is vertical
0019        @param mode This is the original mode
0020        @param parent Parent of the widget
0021     */
0022     ValueLabel(bool isVert, typename CurveParamWidget<CurveWidget_t>::CurveModes mode, QWidget *parent)
0023         : QLabel(parent)
0024         , m_mode(mode)
0025         , m_isVert(isVert)
0026     {
0027         if (m_isVert) {
0028             setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred);
0029             setFixedWidth(10);
0030         } else {
0031             setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed);
0032             setFixedHeight(10);
0033         }
0034         setScaledContents(true);
0035     }
0036 
0037 public Q_SLOTS:
0038     void setMode(typename CurveParamWidget<CurveWidget_t>::CurveModes m)
0039     {
0040         m_mode = m;
0041         createPixmap();
0042     }
0043 
0044 private:
0045     using CurveModes = typename CurveParamWidget<CurveWidget_t>::CurveModes;
0046     void createPixmap()
0047     {
0048         QTransform t;
0049         QSize s = size();
0050         if (!m_isVert) {
0051             t.rotate(90);
0052             s.setHeight(size().width());
0053             s.setWidth(size().height());
0054         }
0055         if (m_mode == CurveModes::Hue) {
0056             setPixmap(QPixmap::fromImage(ColorTools::hsvCurvePlane(s, QColor::fromHsv(200, 200, 200), ColorTools::COM_H, ColorTools::COM_H)).transformed(t));
0057         } else if (m_mode == CurveModes::Saturation) {
0058             setPixmap(QPixmap());
0059         } else {
0060             auto color = CurveParamWidget<CurveWidget_t>::modeToColorsRGB(m_mode);
0061             setPixmap(QPixmap::fromImage(ColorTools::rgbCurveLine(s, color, palette().window().color().rgb())).transformed(t));
0062         }
0063     }
0064 
0065     typename CurveParamWidget<CurveWidget_t>::CurveModes m_mode;
0066     bool m_isVert;
0067 };
0068 
0069 template <> void CurveParamWidget<KisCurveWidget>::slotUpdatePointP(double, bool final)
0070 {
0071     m_edit->updateCurrentPoint(QPointF(m_pX->value(), m_pY->value()), final);
0072 }
0073 
0074 template <> void CurveParamWidget<BezierSplineEditor>::slotUpdatePointP(double, bool final)
0075 {
0076     BPoint p = m_edit->getCurrentPoint();
0077     p.setP(QPointF(m_pX->value(), m_pY->value()));
0078     m_edit->updateCurrentPoint(p, final);
0079 }
0080 
0081 template <> void CurveParamWidget<BezierSplineEditor>::slotUpdatePointH1(double /*value*/, bool final)
0082 {
0083     BPoint p = m_edit->getCurrentPoint();
0084     p.setH1(QPointF(m_h1X->value(), m_h1Y->value()));
0085     m_edit->updateCurrentPoint(p, final);
0086 }
0087 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::slotUpdatePointH1(double /*value*/, bool /*final*/) {}
0088 
0089 template <> void CurveParamWidget<BezierSplineEditor>::slotUpdatePointH2(double /*value*/, bool final)
0090 {
0091     BPoint p = m_edit->getCurrentPoint();
0092     p.setH2(QPointF(m_h2X->value(), m_h2Y->value()));
0093     m_edit->updateCurrentPoint(p, final);
0094 }
0095 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::slotUpdatePointH2(double /*value*/, bool /*final*/) {}
0096 
0097 template <> void CurveParamWidget<BezierSplineEditor>::slotSetHandlesLinked(bool linked)
0098 {
0099     BPoint p = m_edit->getCurrentPoint();
0100     p.setHandlesLinked(linked);
0101     m_edit->updateCurrentPoint(p);
0102 }
0103 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::slotSetHandlesLinked(bool /*linked*/) {}
0104 
0105 template <> void CurveParamWidget<BezierSplineEditor>::slotShowAllHandles(bool show)
0106 {
0107     m_edit->setShowAllHandles(show);
0108     KdenliveSettings::setBezier_showallhandles(show);
0109 }
0110 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::slotShowAllHandles(bool /*show*/) {}
0111 template <typename CurveWidget_t>
0112 
0113 CurveParamWidget<CurveWidget_t>::CurveParamWidget(std::shared_ptr<AssetParameterModel> model, QModelIndex index, QWidget *parent)
0114     : AbstractParamWidget(std::move(model), index, parent)
0115     , m_mode(CurveModes::Luma)
0116     , m_showPixmap(KdenliveSettings::bezier_showpixmap())
0117 {
0118     // construct curve editor
0119     m_edit = new CurveWidget_t(this);
0120     connect(m_edit, static_cast<void (CurveWidget_t::*)(const Point_t &, bool)>(&CurveWidget_t::currentPoint), this,
0121             static_cast<void (CurveParamWidget<CurveWidget_t>::*)(const Point_t &, bool)>(&CurveParamWidget<CurveWidget_t>::slotUpdatePointEntries));
0122 
0123     // construct and fill layout
0124     auto *layout = new QVBoxLayout(this);
0125     layout->setSpacing(0);
0126     setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
0127     layout->addWidget(m_edit);
0128     m_edit->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Preferred);
0129 
0130     auto *widget = new QWidget(this);
0131     widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum);
0132     m_ui.setupUi(widget);
0133     layout->addWidget(widget);
0134 
0135     // set up icons and initial button states
0136     m_ui.buttonShowPixmap->setIcon(QIcon(QPixmap::fromImage(ColorTools::rgbCurvePlane(QSize(16, 16), ColorTools::ColorsRGB::Luma, 0.8))));
0137     m_ui.widgetPoint->setEnabled(false);
0138     m_edit->setGridLines(KdenliveSettings::bezier_gridlines());
0139     m_ui.buttonShowPixmap->setChecked(KdenliveSettings::bezier_showpixmap());
0140     m_ui.buttonShowAllHandles->setChecked(KdenliveSettings::bezier_showallhandles());
0141     slotShowAllHandles(KdenliveSettings::bezier_showallhandles());
0142 
0143     // connect buttons to their slots
0144     connect(m_ui.buttonLinkHandles, &QAbstractButton::toggled, this, &CurveParamWidget<CurveWidget_t>::slotSetHandlesLinked);
0145     connect(m_ui.buttonDeletePoint, &QAbstractButton::clicked, m_edit, &CurveWidget_t::slotDeleteCurrentPoint);
0146     connect(m_ui.buttonZoomIn, &QAbstractButton::clicked, m_edit, &CurveWidget_t::slotZoomIn);
0147     connect(m_ui.buttonZoomOut, &QAbstractButton::clicked, m_edit, &CurveWidget_t::slotZoomOut);
0148     connect(m_ui.buttonGridChange, &QAbstractButton::clicked, this, &CurveParamWidget<CurveWidget_t>::slotGridChange);
0149     connect(m_ui.buttonShowPixmap, &QAbstractButton::toggled, this, &CurveParamWidget<CurveWidget_t>::slotShowPixmap);
0150     connect(m_ui.buttonResetSpline, &QAbstractButton::clicked, m_edit, &CurveWidget_t::reset);
0151     connect(m_ui.buttonShowAllHandles, &QAbstractButton::toggled, this, &CurveParamWidget<CurveWidget_t>::slotShowAllHandles);
0152 
0153     setupLayoutPoint();
0154     setupLayoutHandles();
0155     slotRefresh();
0156 
0157     deleteIrrelevantItems();
0158     // emit the signal of the base class when appropriate
0159     connect(m_edit, &CurveWidget_t::modified, [this]() { Q_EMIT valueChanged(m_index, m_edit->toString(), true); });
0160 }
0161 
0162 template <> void CurveParamWidget<KisCurveWidget>::deleteIrrelevantItems()
0163 {
0164     delete m_ui.layoutH1;
0165     delete m_ui.layoutH2;
0166     delete m_ui.buttonLinkHandles;
0167     delete m_ui.handlesLayout;
0168     m_ui.gridLayout->removeWidget(m_ui.buttonShowAllHandles);
0169     delete m_ui.buttonShowAllHandles;
0170 
0171 }
0172 
0173 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::deleteIrrelevantItems()
0174 {
0175     // Nothing to do in general
0176 }
0177 
0178 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::setupLayoutPoint()
0179 {
0180     m_pX = new DragValue(i18n("In"), 0, 3, 0, 1, -1, QString(), false, false, this);
0181     m_pX->setStep(0.001);
0182     m_pY = new DragValue(i18n("Out"), 0, 3, 0, 1, -1, QString(), false, false, this);
0183     m_pY->setStep(0.001);
0184     m_ui.layoutP->addWidget(m_pX);
0185     m_ui.layoutP->addWidget(m_pY);
0186     connect(m_pX, &DragValue::valueChanged, this, &CurveParamWidget<CurveWidget_t>::slotUpdatePointP);
0187     connect(m_pY, &DragValue::valueChanged, this, &CurveParamWidget<CurveWidget_t>::slotUpdatePointP);
0188 }
0189 
0190 template <> void CurveParamWidget<BezierSplineEditor>::setupLayoutHandles()
0191 {
0192     m_h1X = new DragValue(i18n("X"), 0, 3, -2, 2, -1, QString(), false, false, this);
0193     m_h1X->setStep(0.001);
0194     m_h1Y = new DragValue(i18n("Y"), 0, 3, -2, 2, -1, QString(), false, false, this);
0195     m_h1Y->setStep(0.001);
0196     m_h2X = new DragValue(i18n("X"), 0, 3, -2, 2, -1, QString(), false, false, this);
0197     m_h2X->setStep(0.001);
0198     m_h2Y = new DragValue(i18n("Y"), 0, 3, -2, 2, -1, QString(), false, false, this);
0199     m_h2Y->setStep(0.001);
0200     m_ui.layoutH1->addWidget(new QLabel(i18n("Handle 1:")));
0201     m_ui.layoutH1->addWidget(m_h1X);
0202     m_ui.layoutH1->addWidget(m_h1Y);
0203     m_ui.layoutH2->addWidget(new QLabel(i18n("Handle 2:")));
0204     m_ui.layoutH2->addWidget(m_h2X);
0205     m_ui.layoutH2->addWidget(m_h2Y);
0206     connect(m_h1X, &DragValue::valueChanged, this, &CurveParamWidget<BezierSplineEditor>::slotUpdatePointH1);
0207     connect(m_h1Y, &DragValue::valueChanged, this, &CurveParamWidget<BezierSplineEditor>::slotUpdatePointH1);
0208     connect(m_h2X, &DragValue::valueChanged, this, &CurveParamWidget<BezierSplineEditor>::slotUpdatePointH2);
0209     connect(m_h2Y, &DragValue::valueChanged, this, &CurveParamWidget<BezierSplineEditor>::slotUpdatePointH2);
0210 }
0211 
0212 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::setupLayoutHandles()
0213 {
0214     // Nothing to do in general
0215 }
0216 
0217 template <typename CurveWidget_t> QString CurveParamWidget<CurveWidget_t>::toString() const
0218 {
0219     return m_edit->toString();
0220 }
0221 
0222 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::setMode(CurveModes mode)
0223 {
0224     if (m_mode != mode) {
0225         m_mode = mode;
0226         if (m_showPixmap) {
0227             slotShowPixmap(true);
0228         }
0229     }
0230 }
0231 
0232 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::slotGridChange()
0233 {
0234     m_edit->setGridLines((m_edit->gridLines() + 1) % 9);
0235     KdenliveSettings::setBezier_gridlines(m_edit->gridLines());
0236 }
0237 
0238 template <typename CurveWidget_t> ColorTools::ColorsRGB CurveParamWidget<CurveWidget_t>::modeToColorsRGB(CurveModes mode)
0239 {
0240     switch (mode) {
0241     case CurveModes::Red:
0242         return ColorTools::ColorsRGB::R;
0243     case CurveModes::Green:
0244         return ColorTools::ColorsRGB::G;
0245     case CurveModes::Blue:
0246         return ColorTools::ColorsRGB::B;
0247     case CurveModes::Luma:
0248         return ColorTools::ColorsRGB::Luma;
0249     case CurveModes::Alpha:
0250         return ColorTools::ColorsRGB::A;
0251     case CurveModes::RGB:
0252     case CurveModes::Hue:
0253     case CurveModes::Saturation:
0254     default:
0255         return ColorTools::ColorsRGB::RGB;
0256     }
0257     return ColorTools::ColorsRGB::RGB;
0258 }
0259 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::slotShowPixmap(bool show)
0260 {
0261     m_showPixmap = show;
0262     KdenliveSettings::setBezier_showpixmap(show);
0263     if (show) {
0264         if (m_mode == CurveModes::Hue) {
0265             m_edit->setPixmap(
0266                 QPixmap::fromImage(ColorTools::hsvCurvePlane(m_edit->size(), QColor::fromHsv(200, 200, 200), ColorTools::COM_H, ColorTools::COM_H)));
0267         } else if (m_mode == CurveModes::Saturation) {
0268             m_edit->setPixmap(QPixmap());
0269         } else {
0270             auto color = modeToColorsRGB(m_mode);
0271             m_edit->setPixmap(QPixmap::fromImage(ColorTools::rgbCurvePlane(m_edit->size(), color, 1, palette().window().color().rgb())));
0272         }
0273     } else {
0274         m_edit->setPixmap(QPixmap());
0275     }
0276 }
0277 
0278 template <> void CurveParamWidget<BezierSplineEditor>::slotUpdatePointEntries(const BPoint &p, bool extremal)
0279 {
0280     blockSignals(true);
0281     if (p == BPoint()) {
0282         m_ui.widgetPoint->setEnabled(false);
0283     } else {
0284         m_ui.widgetPoint->setEnabled(true);
0285         // disable irrelevant buttons if the point is extremal
0286         m_pX->setEnabled(!extremal);
0287         m_ui.buttonDeletePoint->setEnabled(!extremal);
0288         m_ui.buttonLinkHandles->setEnabled(!extremal);
0289         if (extremal && p.p.x() + 1e-4 >= 1.00) { // last point
0290             m_h2X->setEnabled(false);
0291             m_h2Y->setEnabled(false);
0292         } else {
0293             m_h2X->setEnabled(true);
0294             m_h2Y->setEnabled(true);
0295         }
0296         if (extremal && p.p.x() <= 0.01) { // first point
0297             m_h1X->setEnabled(false);
0298             m_h1Y->setEnabled(false);
0299         } else {
0300             m_h1X->setEnabled(true);
0301             m_h1Y->setEnabled(true);
0302         }
0303 
0304         for (auto elem : {m_pX, m_pY, m_h1X, m_h1Y, m_h2X, m_h2Y}) {
0305             elem->blockSignals(true);
0306         }
0307         m_pX->setValue(p.p.x());
0308         m_pY->setValue(p.p.y());
0309         m_h1X->setValue(p.h1.x());
0310         m_h1Y->setValue(p.h1.y());
0311         m_h2X->setValue(p.h2.x());
0312         m_h2Y->setValue(p.h2.y());
0313         for (auto elem : {m_pX, m_pY, m_h1X, m_h1Y, m_h2X, m_h2Y}) {
0314             elem->blockSignals(false);
0315         }
0316         m_ui.buttonLinkHandles->setChecked(p.handlesLinked);
0317     }
0318     blockSignals(false);
0319 }
0320 
0321 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::slotUpdatePointEntries(const BPoint &p, bool extremal)
0322 {
0323     Q_UNUSED(p);
0324     Q_UNUSED(extremal);
0325     // Wrong slot called in curve widget
0326     Q_ASSERT(false);
0327 }
0328 
0329 template <> void CurveParamWidget<KisCurveWidget>::slotUpdatePointEntries(const QPointF &p, bool extremal)
0330 {
0331     blockSignals(true);
0332     if (p == QPointF()) {
0333         m_ui.widgetPoint->setEnabled(false);
0334     } else {
0335         m_ui.widgetPoint->setEnabled(true);
0336         // disable irrelevant buttons if the point is extremal
0337         m_pX->setEnabled(!extremal);
0338         m_ui.buttonDeletePoint->setEnabled(!extremal);
0339 
0340         for (auto elem : {m_pX, m_pY}) {
0341             elem->blockSignals(true);
0342         }
0343         m_pX->setValue(p.x());
0344         m_pY->setValue(p.y());
0345         for (auto elem : {m_pX, m_pY}) {
0346             elem->blockSignals(false);
0347         }
0348     }
0349     blockSignals(false);
0350 }
0351 
0352 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::slotUpdatePointEntries(const QPointF &p, bool extremal)
0353 {
0354     Q_UNUSED(p);
0355     Q_UNUSED(extremal);
0356     // Wrong slot called in curve widget
0357     Q_ASSERT(false);
0358 }
0359 
0360 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::slotShowComment(bool show)
0361 {
0362     Q_UNUSED(show);
0363 }
0364 
0365 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::slotRefresh()
0366 {
0367     if (m_model->data(m_index, AssetParameterModel::TypeRole).template value<ParamType>() == ParamType::Curve) {
0368         QList<QPointF> points;
0369         int number = qRound(m_model->data(m_index, AssetParameterModel::Enum3Role).toDouble() * 10);
0370         int start = m_model->data(m_index, AssetParameterModel::MinRole).toInt();
0371         // for the curve, inpoints are numbered: 6, 8, 10, 12, 14
0372         // outpoints, 7, 9, 11, 13,15 so we need to deduce these enums
0373         int inRef = int(AssetParameterModel::Enum6Role) + 2 * (start - 1);
0374         int outRef = int(AssetParameterModel::Enum7Role) + 2 * (start - 1);
0375         for (int j = start; j <= number; ++j) {
0376             double inVal = m_model->data(m_index, AssetParameterModel::DataRoles(inRef)).toDouble();
0377             double outVal = m_model->data(m_index, AssetParameterModel::DataRoles(outRef)).toDouble();
0378             points << QPointF(inVal, outVal);
0379             inRef += 2;
0380             outRef += 2;
0381         }
0382         if (!points.isEmpty()) {
0383             m_edit->setFromString(KisCubicCurve(points).toString());
0384         }
0385     } else {
0386         m_edit->setFromString(m_model->data(m_index, AssetParameterModel::ValueRole).toString());
0387     }
0388 }
0389 
0390 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::setMaxPoints(int max)
0391 {
0392     m_edit->setMaxPoints(max);
0393 }
0394 
0395 template <typename CurveWidget_t> void CurveParamWidget<CurveWidget_t>::resizeEvent(QResizeEvent *e)
0396 {
0397     QWidget::resizeEvent(e);
0398     Q_EMIT updateHeight();
0399 }