diff --git a/src/assets/view/widgets/colorwheel.cpp b/src/assets/view/widgets/colorwheel.cpp index b3e72e9b6..6ba368da7 100644 --- a/src/assets/view/widgets/colorwheel.cpp +++ b/src/assets/view/widgets/colorwheel.cpp @@ -1,398 +1,398 @@ /* * 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 QPointF &point) { if (!m_image.valid(point.toPoint())) { 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) { if (event->modifiers() & Qt::ShiftModifier) { QPoint clicked = event->pos(); if (m_wheelRegion.contains(clicked)) { QPointF current = pointForColor(); QPointF diff = clicked - current; double factor = fabs(diff.x()) > fabs(diff.y()) ? fabs(diff.x()) : fabs(diff.y()); diff /= factor; m_lastPoint = current + diff; } else if (m_sliderRegion.contains(clicked)) { double y = yForColor(); int offset = clicked.y() > y ? 1 : -1; m_lastPoint = QPointF(clicked.x(), y + offset); } else { return; } } else { m_lastPoint = event->pos(); } if (m_wheelRegion.contains(m_lastPoint.toPoint())) { 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.toPoint())) { 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) { if (!m_isMouseDown) { return; } if (event->modifiers() & Qt::ShiftModifier) { if (m_isInWheel) { QPointF diff = event->pos() - m_lastPoint; double factor = fabs(diff.x()) > fabs(diff.y()) ? fabs(diff.x()) : fabs(diff.y()); diff /= factor; m_lastPoint += diff; } else if (m_isInSquare) { double y = yForColor(); int offset = event->pos().y() > y ? 1 : -1; m_lastPoint = QPointF(event->pos().x(), y + offset); } else { return; } } else { m_lastPoint = event->pos(); } if (m_wheelRegion.contains(m_lastPoint.toPoint()) && m_isInWheel) { const NegQColor color = colorForPoint(m_lastPoint); changeColor(color); } else if (m_sliderRegion.contains(m_lastPoint.toPoint()) && 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()); + m_image.fill(palette().window().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(); } QPointF ColorWheel::pointForColor() { int r = wheelSize() / 2; QTransform transform; transform.translate(r, r); transform.rotate(255 - m_color.hue()); transform.translate(m_color.saturationF() * r, 0); return transform.map(QPointF(0, 0)); } double ColorWheel::yForColor() { qreal value = 1.0 - m_color.valueF(); if (m_id == QLatin1String("lift")) { value -= m_zeroShift; } int ws = wheelSize(); int h = ws - m_margin * 2; return m_margin + value * h; } 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/curves/abstractcurvewidget.ipp b/src/assets/view/widgets/curves/abstractcurvewidget.ipp index c2a7bd9ac..5d484d44f 100644 --- a/src/assets/view/widgets/curves/abstractcurvewidget.ipp +++ b/src/assets/view/widgets/curves/abstractcurvewidget.ipp @@ -1,242 +1,242 @@ /*************************************************************************** * Copyright (C) 2016 by Nicolas Carion * * * * 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 #include #include template AbstractCurveWidget::AbstractCurveWidget(QWidget *parent) : __dummy_AbstractCurveWidget(parent) , m_pixmapCache(nullptr) { setMouseTracking(true); setAutoFillBackground(false); setAttribute(Qt::WA_OpaquePaintEvent); setMinimumSize(150, 150); QSizePolicy sp(QSizePolicy::Preferred, QSizePolicy::MinimumExpanding); sp.setHeightForWidth(true); // force widget to have a height dependent on width; setSizePolicy(sp); setFocusPolicy(Qt::StrongFocus); } template void AbstractCurveWidget::paintBackground(QPainter *p) { /* * Zoom */ m_wWidth = width() - 1; m_wHeight = height() - 1; int offsetX = 1 / 8. * m_zoomLevel * m_wWidth; int offsetY = 1 / 8. * m_zoomLevel * m_wHeight; m_wWidth -= 2 * offsetX; m_wHeight -= 2 * offsetY; p->translate(offsetX, offsetY); /* * Background */ - p->fillRect(rect().translated(-offsetX, -offsetY), palette().background()); + p->fillRect(rect().translated(-offsetX, -offsetY), palette().window()); if (!m_pixmap.isNull()) { if (m_pixmapIsDirty || !m_pixmapCache) { m_pixmapCache = std::make_shared(m_wWidth + 1, m_wHeight + 1); QPainter cachePainter(m_pixmapCache.get()); cachePainter.scale(1.0 * (m_wWidth + 1) / m_pixmap.width(), 1.0 * (m_wHeight + 1) / m_pixmap.height()); cachePainter.drawPixmap(0, 0, m_pixmap); m_pixmapIsDirty = false; } p->drawPixmap(0, 0, *m_pixmapCache); } // select color of the grid, depending on whether we have a palette or not if (!m_pixmap.isNull()) { p->setPen(QPen(palette().mid().color(), 1, Qt::SolidLine)); } else { int h, s, l, a; auto bg = palette().color(QPalette::Window); bg.getHsl(&h, &s, &l, &a); l = (l > 128) ? l - 30 : l + 30; bg.setHsl(h, s, l, a); p->setPen(QPen(bg, 1, Qt::SolidLine)); } /* * Borders */ p->drawRect(0, 0, m_wWidth, m_wHeight); /* * Grid */ if (m_gridLines != 0) { double stepH = m_wWidth / (double)(m_gridLines + 1); double stepV = m_wHeight / (double)(m_gridLines + 1); for (int i = 1; i <= m_gridLines; ++i) { p->drawLine(QLineF(i * stepH, 0, i * stepH, m_wHeight)); p->drawLine(QLineF(0, i * stepV, m_wWidth, i * stepV)); } } p->setRenderHint(QPainter::Antialiasing); /* * Standard line */ p->drawLine(QLineF(0, m_wHeight, m_wWidth, 0)); } template void AbstractCurveWidget::setMaxPoints(int max) { Q_ASSERT(max >= 2); m_maxPoints = max; } template void AbstractCurveWidget::setPixmap(const QPixmap &pix) { m_pixmap = pix; m_pixmapIsDirty = true; update(); } template int AbstractCurveWidget::gridLines() const { return m_gridLines; } template void AbstractCurveWidget::setGridLines(int lines) { m_gridLines = qBound(0, lines, 8); update(); } template void AbstractCurveWidget::slotZoomIn() { m_zoomLevel = qMax(m_zoomLevel - 1, 0); m_pixmapIsDirty = true; update(); } template void AbstractCurveWidget::slotZoomOut() { m_zoomLevel = qMin(m_zoomLevel + 1, 3); m_pixmapIsDirty = true; update(); } template void AbstractCurveWidget::setFromString(const QString &str) { m_curve.fromString(str); m_currentPointIndex = -1; emit currentPoint(Point_t(), true); update(); } template void AbstractCurveWidget::reset() { setFromString(Curve_t().toString()); m_currentPointIndex = -1; emit currentPoint(Point_t(), true); emit modified(); update(); } template QString AbstractCurveWidget::toString() { return m_curve.toString(); } template void AbstractCurveWidget::updateCurrentPoint(const Point_t &p, bool final) { if (m_currentPointIndex >= 0) { m_curve.setPoint(m_currentPointIndex, p); // during validation the point might have changed emit currentPoint(m_curve.getPoint(m_currentPointIndex), isCurrentPointExtremal()); if (final) { emit modified(); } update(); } } template typename AbstractCurveWidget::Point_t AbstractCurveWidget::getCurrentPoint() { if (m_currentPointIndex >= 0) { return m_curve.getPoint(m_currentPointIndex); } else { return Point_t(); } } template bool AbstractCurveWidget::isCurrentPointExtremal() { return m_currentPointIndex == 0 || m_currentPointIndex == m_curve.points().size() - 1; } template void AbstractCurveWidget::slotDeleteCurrentPoint() { if (m_currentPointIndex > 0 && m_currentPointIndex < m_curve.points().size() - 1) { m_curve.removePoint(m_currentPointIndex); m_currentPointIndex--; emit currentPoint(m_curve.getPoint(m_currentPointIndex), isCurrentPointExtremal()); update(); emit modified(); setCursor(Qt::ArrowCursor); m_state = State_t::NORMAL; } } template void AbstractCurveWidget::resizeEvent(QResizeEvent *e) { m_pixmapIsDirty = true; QWidget::resizeEvent(e); } template void AbstractCurveWidget::leaveEvent(QEvent *event) { QWidget::leaveEvent(event); } template void AbstractCurveWidget::mouseReleaseEvent(QMouseEvent *event) { if (event->button() != Qt::LeftButton) { return; } setCursor(Qt::ArrowCursor); m_state = State_t::NORMAL; emit modified(); } template void AbstractCurveWidget::keyPressEvent(QKeyEvent *e) { if (e->key() == Qt::Key_Delete || e->key() == Qt::Key_Backspace) { slotDeleteCurrentPoint(); } else { QWidget::keyPressEvent(e); } } template int AbstractCurveWidget::heightForWidth(int w) const { return w; } diff --git a/src/assets/view/widgets/curves/curveparamwidget.ipp b/src/assets/view/widgets/curves/curveparamwidget.ipp index 2f40d5273..56c61cf06 100644 --- a/src/assets/view/widgets/curves/curveparamwidget.ipp +++ b/src/assets/view/widgets/curves/curveparamwidget.ipp @@ -1,428 +1,428 @@ /*************************************************************************** * 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 . * ***************************************************************************/ #include "bezier/beziersplineeditor.h" #include "colortools.h" #include "cubic/kis_curve_widget.h" #include "kdenlivesettings.h" #include "widgets/dragvalue.h" #include /*@brief this label is a pixmap corresponding to a legend of the axis*/ template class ValueLabel : public QLabel { public: /**@brief Creates the widget @param isVert This parameter is true if the widget is vertical @param mode This is the original mode @param parent Parent of the widget */ ValueLabel(bool isVert, typename CurveParamWidget::CurveModes mode, QWidget *parent) : QLabel(parent) , m_mode(mode) , m_isVert(isVert) { if (m_isVert) { setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Preferred); setFixedWidth(10); } else { setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Fixed); setFixedHeight(10); } setScaledContents(true); } public slots: void setMode(typename CurveParamWidget::CurveModes m) { m_mode = m; createPixmap(); } private: using CurveModes = typename CurveParamWidget::CurveModes; void createPixmap() { QTransform t; QSize s = size(); if (!m_isVert) { t.rotate(90); s.setHeight(size().width()); s.setWidth(size().height()); } if (m_mode == CurveModes::Hue) { setPixmap(QPixmap::fromImage(ColorTools::hsvCurvePlane(s, QColor::fromHsv(200, 200, 200), ColorTools::COM_H, ColorTools::COM_H)).transformed(t)); } else if (m_mode == CurveModes::Saturation) { setPixmap(QPixmap()); } else { auto color = CurveParamWidget::modeToColorsRGB(m_mode); setPixmap(QPixmap::fromImage(ColorTools::rgbCurveLine(s, color, palette().background().color().rgb())).transformed(t)); } } typename CurveParamWidget::CurveModes m_mode; bool m_isVert; }; template <> void CurveParamWidget::slotUpdatePointP(double, bool final) { m_edit->updateCurrentPoint(QPointF(m_pX->value(), m_pY->value()), final); } template <> void CurveParamWidget::slotUpdatePointP(double, bool final) { BPoint p = m_edit->getCurrentPoint(); p.setP(QPointF(m_pX->value(), m_pY->value())); m_edit->updateCurrentPoint(p, final); } template <> void CurveParamWidget::slotUpdatePointH1(double /*value*/, bool final) { BPoint p = m_edit->getCurrentPoint(); p.setH1(QPointF(m_h1X->value(), m_h1Y->value())); m_edit->updateCurrentPoint(p, final); } template void CurveParamWidget::slotUpdatePointH1(double /*value*/, bool /*final*/) {} template <> void CurveParamWidget::slotUpdatePointH2(double /*value*/, bool final) { BPoint p = m_edit->getCurrentPoint(); p.setH2(QPointF(m_h2X->value(), m_h2Y->value())); m_edit->updateCurrentPoint(p, final); } template void CurveParamWidget::slotUpdatePointH2(double /*value*/, bool /*final*/) {} template <> void CurveParamWidget::slotSetHandlesLinked(bool linked) { BPoint p = m_edit->getCurrentPoint(); p.setHandlesLinked(linked); m_edit->updateCurrentPoint(p); } template void CurveParamWidget::slotSetHandlesLinked(bool /*linked*/) {} template <> void CurveParamWidget::slotShowAllHandles(bool show) { m_edit->setShowAllHandles(show); KdenliveSettings::setBezier_showallhandles(show); } template void CurveParamWidget::slotShowAllHandles(bool /*show*/) {} template CurveParamWidget::CurveParamWidget(std::shared_ptr model, QModelIndex index, QWidget *parent) : AbstractParamWidget(std::move(model), index, parent) , m_mode(CurveModes::Luma) , m_showPixmap(KdenliveSettings::bezier_showpixmap()) { // construct curve editor m_edit = new CurveWidget_t(this); connect(m_edit, static_cast(&CurveWidget_t::currentPoint), this, static_cast::*)(const Point_t &, bool)>(&CurveParamWidget::slotUpdatePointEntries)); // construct and fill layout auto *layout = new QVBoxLayout(this); layout->setSpacing(0); setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); layout->addWidget(m_edit); m_leftParam = new ValueLabel(true, m_mode, this); m_leftParam->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); m_leftParam->setSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed); m_bottomParam = new ValueLabel(false, m_mode, this); m_bottomParam->setFrameStyle(QFrame::StyledPanel | QFrame::Plain); m_bottomParam->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Fixed); // horizontal layout to make sure that everything is centered auto *horiz_layout = new QHBoxLayout; horiz_layout->addWidget(m_leftParam); horiz_layout->addWidget(m_bottomParam); layout->addLayout(horiz_layout); auto *widget = new QWidget(this); widget->setSizePolicy(QSizePolicy::Preferred, QSizePolicy::Maximum); m_ui.setupUi(widget); layout->addWidget(widget); // set up icons and initial button states m_ui.buttonLinkHandles->setIcon(QIcon::fromTheme(QStringLiteral("edit-link"))); m_ui.buttonDeletePoint->setIcon(QIcon::fromTheme(QStringLiteral("list-remove"))); m_ui.buttonZoomIn->setIcon(QIcon::fromTheme(QStringLiteral("zoom-in"))); m_ui.buttonZoomOut->setIcon(QIcon::fromTheme(QStringLiteral("zoom-out"))); m_ui.buttonGridChange->setIcon(QIcon::fromTheme(QStringLiteral("view-grid"))); m_ui.buttonShowPixmap->setIcon(QIcon(QPixmap::fromImage(ColorTools::rgbCurvePlane(QSize(16, 16), ColorTools::ColorsRGB::Luma, (float)0.8)))); m_ui.buttonResetSpline->setIcon(QIcon::fromTheme(QStringLiteral("view-refresh"))); m_ui.buttonShowAllHandles->setIcon(QIcon::fromTheme(QStringLiteral("draw-bezier-curves"))); m_ui.widgetPoint->setEnabled(false); m_edit->setGridLines(KdenliveSettings::bezier_gridlines()); m_ui.buttonShowPixmap->setChecked(KdenliveSettings::bezier_showpixmap()); m_ui.buttonShowAllHandles->setChecked(KdenliveSettings::bezier_showallhandles()); slotShowAllHandles(KdenliveSettings::bezier_showallhandles()); // connect buttons to their slots connect(m_ui.buttonLinkHandles, &QAbstractButton::toggled, this, &CurveParamWidget::slotSetHandlesLinked); connect(m_ui.buttonDeletePoint, &QAbstractButton::clicked, m_edit, &CurveWidget_t::slotDeleteCurrentPoint); connect(m_ui.buttonZoomIn, &QAbstractButton::clicked, m_edit, &CurveWidget_t::slotZoomIn); connect(m_ui.buttonZoomOut, &QAbstractButton::clicked, m_edit, &CurveWidget_t::slotZoomOut); connect(m_ui.buttonGridChange, &QAbstractButton::clicked, this, &CurveParamWidget::slotGridChange); connect(m_ui.buttonShowPixmap, &QAbstractButton::toggled, this, &CurveParamWidget::slotShowPixmap); connect(m_ui.buttonResetSpline, &QAbstractButton::clicked, m_edit, &CurveWidget_t::reset); connect(m_ui.buttonShowAllHandles, &QAbstractButton::toggled, this, &CurveParamWidget::slotShowAllHandles); setupLayoutPoint(); setupLayoutHandles(); slotRefresh(); deleteIrrelevantItems(); // emit the signal of the base class when appropriate connect(m_edit, &CurveWidget_t::modified, [this]() { emit valueChanged(m_index, m_edit->toString(), true); }); } template <> void CurveParamWidget::deleteIrrelevantItems() { m_ui.gridLayout->removeWidget(m_ui.buttonShowAllHandles); delete m_ui.buttonShowAllHandles; } template void CurveParamWidget::deleteIrrelevantItems() { // Nothing to do in general } template void CurveParamWidget::setupLayoutPoint() { m_pX = new DragValue(i18n("In"), 0, 3, 0, 1, -1, QString(), false, this); m_pX->setStep(0.001); m_pY = new DragValue(i18n("Out"), 0, 3, 0, 1, -1, QString(), false, this); m_pY->setStep(0.001); m_ui.layoutP->addWidget(m_pX); m_ui.layoutP->addWidget(m_pY); connect(m_pX, &DragValue::valueChanged, this, &CurveParamWidget::slotUpdatePointP); connect(m_pY, &DragValue::valueChanged, this, &CurveParamWidget::slotUpdatePointP); } template <> void CurveParamWidget::setupLayoutHandles() { m_h1X = new DragValue(i18n("X"), 0, 3, -2, 2, -1, QString(), false, this); m_h1X->setStep(0.001); m_h1Y = new DragValue(i18n("Y"), 0, 3, -2, 2, -1, QString(), false, this); m_h1Y->setStep(0.001); m_h2X = new DragValue(i18n("X"), 0, 3, -2, 2, -1, QString(), false, this); m_h2X->setStep(0.001); m_h2Y = new DragValue(i18n("Y"), 0, 3, -2, 2, -1, QString(), false, this); m_h2Y->setStep(0.001); m_ui.layoutH1->addWidget(new QLabel(i18n("Handle 1:"))); m_ui.layoutH1->addWidget(m_h1X); m_ui.layoutH1->addWidget(m_h1Y); m_ui.layoutH2->addWidget(new QLabel(i18n("Handle 2:"))); m_ui.layoutH2->addWidget(m_h2X); m_ui.layoutH2->addWidget(m_h2Y); connect(m_h1X, &DragValue::valueChanged, this, &CurveParamWidget::slotUpdatePointH1); connect(m_h1Y, &DragValue::valueChanged, this, &CurveParamWidget::slotUpdatePointH1); connect(m_h2X, &DragValue::valueChanged, this, &CurveParamWidget::slotUpdatePointH2); connect(m_h2Y, &DragValue::valueChanged, this, &CurveParamWidget::slotUpdatePointH2); } template void CurveParamWidget::setupLayoutHandles() { // Nothing to do in general } template QString CurveParamWidget::toString() const { return m_edit->toString(); } template void CurveParamWidget::setMode(CurveModes mode) { if (m_mode != mode) { m_mode = mode; if (m_showPixmap) { slotShowPixmap(true); } m_leftParam->setMode(mode); m_bottomParam->setMode(mode); } } template void CurveParamWidget::slotGridChange() { m_edit->setGridLines((m_edit->gridLines() + 1) % 9); KdenliveSettings::setBezier_gridlines(m_edit->gridLines()); } template ColorTools::ColorsRGB CurveParamWidget::modeToColorsRGB(CurveModes mode) { switch (mode) { case CurveModes::Red: return ColorTools::ColorsRGB::R; case CurveModes::Green: return ColorTools::ColorsRGB::G; case CurveModes::Blue: return ColorTools::ColorsRGB::B; case CurveModes::Luma: return ColorTools::ColorsRGB::Luma; case CurveModes::Alpha: return ColorTools::ColorsRGB::A; case CurveModes::RGB: case CurveModes::Hue: case CurveModes::Saturation: default: return ColorTools::ColorsRGB::RGB; } return ColorTools::ColorsRGB::RGB; } template void CurveParamWidget::slotShowPixmap(bool show) { m_showPixmap = show; KdenliveSettings::setBezier_showpixmap(show); if (show) { if (m_mode == CurveModes::Hue) { m_edit->setPixmap( QPixmap::fromImage(ColorTools::hsvCurvePlane(m_edit->size(), QColor::fromHsv(200, 200, 200), ColorTools::COM_H, ColorTools::COM_H))); } else if (m_mode == CurveModes::Saturation) { m_edit->setPixmap(QPixmap()); } else { auto color = modeToColorsRGB(m_mode); - m_edit->setPixmap(QPixmap::fromImage(ColorTools::rgbCurvePlane(m_edit->size(), color, 1, palette().background().color().rgb()))); + m_edit->setPixmap(QPixmap::fromImage(ColorTools::rgbCurvePlane(m_edit->size(), color, 1, palette().window().color().rgb()))); } } else { m_edit->setPixmap(QPixmap()); } } template <> void CurveParamWidget::slotUpdatePointEntries(const BPoint &p, bool extremal) { blockSignals(true); if (p == BPoint()) { m_ui.widgetPoint->setEnabled(false); } else { m_ui.widgetPoint->setEnabled(true); // disable irrelevant buttons if the point is extremal m_pX->setEnabled(!extremal); m_ui.buttonDeletePoint->setEnabled(!extremal); m_ui.buttonLinkHandles->setEnabled(!extremal); if (extremal && p.p.x() + 1e-4 >= 1.00) { // last point m_h2X->setEnabled(false); m_h2Y->setEnabled(false); } else { m_h2X->setEnabled(true); m_h2Y->setEnabled(true); } if (extremal && p.p.x() <= 0.01) { // first point m_h1X->setEnabled(false); m_h1Y->setEnabled(false); } else { m_h1X->setEnabled(true); m_h1Y->setEnabled(true); } for (auto elem : {m_pX, m_pY, m_h1X, m_h1Y, m_h2X, m_h2Y}) { elem->blockSignals(true); } m_pX->setValue(p.p.x()); m_pY->setValue(p.p.y()); m_h1X->setValue(p.h1.x()); m_h1Y->setValue(p.h1.y()); m_h2X->setValue(p.h2.x()); m_h2Y->setValue(p.h2.y()); for (auto elem : {m_pX, m_pY, m_h1X, m_h1Y, m_h2X, m_h2Y}) { elem->blockSignals(false); } m_ui.buttonLinkHandles->setChecked(p.handlesLinked); } blockSignals(false); } template void CurveParamWidget::slotUpdatePointEntries(const BPoint &p, bool extremal) { Q_UNUSED(p); Q_UNUSED(extremal); // Wrong slot called in curve widget Q_ASSERT(false); } template <> void CurveParamWidget::slotUpdatePointEntries(const QPointF &p, bool extremal) { blockSignals(true); if (p == QPointF()) { m_ui.widgetPoint->setEnabled(false); } else { m_ui.widgetPoint->setEnabled(true); // disable irrelevant buttons if the point is extremal m_pX->setEnabled(!extremal); m_ui.buttonDeletePoint->setEnabled(!extremal); for (auto elem : {m_pX, m_pY}) { elem->blockSignals(true); } m_pX->setValue(p.x()); m_pY->setValue(p.y()); for (auto elem : {m_pX, m_pY}) { elem->blockSignals(false); } } blockSignals(false); } template void CurveParamWidget::slotUpdatePointEntries(const QPointF &p, bool extremal) { Q_UNUSED(p); Q_UNUSED(extremal); // Wrong slot called in curve widget Q_ASSERT(false); } template void CurveParamWidget::slotShowComment(bool show) { Q_UNUSED(show); } template void CurveParamWidget::slotRefresh() { if (m_model->data(m_index, AssetParameterModel::TypeRole).template value() == ParamType::Curve) { QList points; QLocale locale; // Rounding gives really weird results. (int) (10 * 0.3) gives 2! So for now, add 0.5 to get correct result int number = m_model->data(m_index, AssetParameterModel::Enum3Role).toDouble() * 10 + 0.5; int start = m_model->data(m_index, AssetParameterModel::MinRole).toInt(); // for the curve, inpoints are numbered: 6, 8, 10, 12, 14 // outpoints, 7, 9, 11, 13,15 so we need to deduce these enums int inRef = (int)AssetParameterModel::Enum6Role + 2 * (start - 1); int outRef = (int)AssetParameterModel::Enum7Role + 2 * (start - 1); for (int j = start; j <= number; ++j) { double inVal = m_model->data(m_index, (AssetParameterModel::DataRoles)inRef).toDouble(); double outVal = m_model->data(m_index, (AssetParameterModel::DataRoles)outRef).toDouble(); points << QPointF(inVal, outVal); inRef += 2; outRef += 2; } if (!points.isEmpty()) { m_edit->setFromString(KisCubicCurve(points).toString()); } } else { m_edit->setFromString(m_model->data(m_index, AssetParameterModel::ValueRole).toString()); } } template void CurveParamWidget::setMaxPoints(int max) { m_edit->setMaxPoints(max); }