File indexing completed on 2024-05-12 16:02:03

0001 /*
0002  * KDE. Krita Project.
0003  *
0004  * SPDX-FileCopyrightText: 2021 Deif Lou <ginoba@gmail.com>
0005  *
0006  * SPDX-License-Identifier: GPL-2.0-or-later
0007  */
0008 
0009 #include <QPainter>
0010 #include <QMouseEvent>
0011 
0012 #include <algorithm>
0013 #include <cmath>
0014 
0015 #include <kis_painting_tweaks.h>
0016 
0017 #include "KisLevelsSlider.h"
0018 
0019 KisLevelsSlider::KisLevelsSlider(QWidget *parent)
0020     : QWidget(parent)
0021     , m_constrainPositions(true)
0022     , m_selectedHandle(-1)
0023     , m_hoveredHandle(-1)
0024 {
0025     setFocusPolicy(Qt::WheelFocus);
0026     setMouseTracking(true);
0027 }
0028 
0029 KisLevelsSlider::~KisLevelsSlider()
0030 {}
0031 
0032 qreal KisLevelsSlider::handlePosition(int handleIndex) const
0033 {
0034     Q_ASSERT(handleIndex >= 0 && handleIndex < m_handles.size());
0035 
0036     return m_handles[handleIndex].position;
0037 }
0038 
0039 QColor KisLevelsSlider::handleColor(int handleIndex) const
0040 {
0041     Q_ASSERT(handleIndex >= 0 && handleIndex < m_handles.size());
0042 
0043     return m_handles[handleIndex].color;
0044 }
0045 
0046 void KisLevelsSlider::setHandlePosition(int handleIndex, qreal newPosition)
0047 {
0048     Q_ASSERT(handleIndex >= 0 && handleIndex < m_handles.size());
0049 
0050     if (m_constrainPositions) {
0051         newPosition =
0052             qBound(
0053                 handleIndex == m_handles.first().index ? 0.0 : m_handles[handleIndex - 1].position + minimumSpaceBetweenHandles,
0054                 newPosition,
0055                 handleIndex == m_handles.last().index ? 1.0 : m_handles[handleIndex + 1].position - minimumSpaceBetweenHandles
0056             );
0057     } else {
0058         newPosition = qBound(0.0, newPosition, 1.0);
0059     }
0060 
0061     if (newPosition == m_handles[handleIndex].position) {
0062         return;
0063     }
0064 
0065     m_handles[handleIndex].position = newPosition;
0066 
0067     update();
0068     emit handlePositionChanged(handleIndex, newPosition);
0069 }
0070 
0071 void KisLevelsSlider::setHandleColor(int handleIndex, const QColor &newColor)
0072 {
0073     Q_ASSERT(handleIndex >= 0 && handleIndex < m_handles.size());
0074 
0075     if (newColor == m_handles[handleIndex].color) {
0076         return;
0077     }
0078 
0079     m_handles[handleIndex].color = newColor;
0080     
0081     update();
0082     emit handleColorChanged(handleIndex, newColor);
0083 }
0084 
0085 QSize KisLevelsSlider::sizeHint() const
0086 {
0087     return QSize(256, 20) + QSize(handleWidth, handleHeight);
0088 }
0089 
0090 QSize KisLevelsSlider::minimumSizeHint() const
0091 {
0092     return QSize(128, 20) + QSize(handleWidth, handleHeight);
0093 }
0094 
0095 QRect KisLevelsSlider::gradientRect() const
0096 {
0097     const int margin = handleWidth / 2;
0098     return rect().adjusted(margin, 0, -margin, -handleHeight);
0099 }
0100 
0101 QVector<KisLevelsSlider::Handle> KisLevelsSlider::sortedHandles() const
0102 {
0103     QVector<Handle> sortedHandles_ = m_handles;
0104     std::sort(sortedHandles_.begin(), sortedHandles_.end(),
0105         [](const Handle &lhs, const Handle &rhs)
0106         {
0107             return qFuzzyCompare(lhs.position, rhs.position) ? lhs.index < rhs.index : lhs.position < rhs.position;
0108         }
0109     );
0110     return sortedHandles_;
0111 }
0112 
0113 int KisLevelsSlider::closestHandleToPosition(qreal position) const
0114 {
0115     const QVector<Handle> sortedHandles_ = sortedHandles();
0116     int handleIndex = -1;
0117 
0118     if (position <= sortedHandles_.first().position) {
0119         handleIndex = sortedHandles_.first().index;
0120     } else if (position >= sortedHandles_.last().position) {
0121         handleIndex = sortedHandles_.last().index;
0122     } else {
0123         for (int i = 0; i < sortedHandles_.size() - 1; ++i) {
0124             if (position >= sortedHandles_[i + 1].position) {
0125                 continue;
0126             }
0127             const qreal middlePoint = (sortedHandles_[i].position + sortedHandles_[i + 1].position) / 2.0;
0128             handleIndex = position <= middlePoint ? sortedHandles_[i].index : sortedHandles_[i + 1].index;
0129             break;
0130         }
0131     }
0132 
0133     return handleIndex;
0134 }
0135 
0136 qreal KisLevelsSlider::positionFromX(int x) const
0137 {
0138     const QRect gradientRect_ = gradientRect();
0139     return static_cast<qreal>(x - gradientRect_.left()) / static_cast<qreal>(gradientRect_.width());
0140 }
0141 
0142 int KisLevelsSlider::closestHandleToX(int x) const
0143 {
0144     return closestHandleToPosition(positionFromX(x));
0145 }
0146 
0147 int KisLevelsSlider::xFromPosition(qreal position) const
0148 {
0149     const QRect gradientRect_ = gradientRect();
0150     return static_cast<int>(position * static_cast<qreal>(gradientRect_.width())) + gradientRect_.left();
0151 }
0152 
0153 void KisLevelsSlider::handleIncrementInput(int direction, Qt::KeyboardModifiers modifiers)
0154 {
0155     if (direction == 0) {
0156         return;
0157     }
0158     if (modifiers & Qt::ControlModifier) {
0159         m_selectedHandle += direction < 0 ? -1 : 1;
0160         m_selectedHandle = qBound(0, m_selectedHandle, m_handles.size() - 1);
0161         update();
0162     } else if (m_selectedHandle >= 0 && m_selectedHandle < m_handles.size()) {
0163         const qreal increment = modifiers & Qt::ShiftModifier ? slowPositionIncrement : normalPositionIncrement;
0164         const qreal position = m_handles[m_selectedHandle].position + (direction < 0 ? -increment : increment);
0165         setHandlePosition(m_selectedHandle, position);
0166     }
0167 }
0168 
0169 void KisLevelsSlider::paintHandle(QPainter &painter, const QRect &rect, const Handle &handle)
0170 {
0171     painter.setRenderHint(QPainter::Antialiasing, false);
0172     const int halfHandleWidth = handleWidth / 2.0;
0173     {
0174         const QPolygon shape({
0175             {rect.left() + halfHandleWidth, rect.top()},
0176             {rect.right() + 1, rect.top() + halfHandleWidth},
0177             {rect.right() + 1, rect.bottom() + 1},
0178             {rect.left(), rect.bottom() + 1},
0179             {rect.left(), rect.top() + halfHandleWidth}
0180         });
0181         painter.setPen(Qt::NoPen);
0182         const bool isSelected = handle.index == m_selectedHandle;
0183         QColor brushColor =
0184             isSelected && hasFocus()
0185             ? KisPaintingTweaks::blendColors(handle.color, palette().highlight().color(), 0.25)
0186             : handle.color;
0187         if (!isEnabled()) {
0188             brushColor.setAlpha(64);
0189         }
0190         painter.setBrush(brushColor);
0191         painter.drawPolygon(shape);
0192     }
0193     {
0194         const QPolygon shape({
0195             {rect.left() + halfHandleWidth, rect.top()},
0196             {rect.right(), rect.top() + halfHandleWidth},
0197             {rect.right(), rect.bottom()},
0198             {rect.left(), rect.bottom()},
0199             {rect.left(), rect.top() + halfHandleWidth}
0200         });
0201         const bool isHovered = handle.index == m_hoveredHandle;
0202         QColor penColor = isHovered && isEnabled() ? palette().highlight().color() : palette().text().color();
0203         if (!isHovered) {
0204             penColor.setAlpha(64);
0205         }
0206         painter.setPen(penColor);
0207         painter.setBrush(Qt::NoBrush);
0208         painter.drawPolygon(shape);
0209     }
0210 }
0211 
0212 void KisLevelsSlider::paintEvent(QPaintEvent *e)
0213 {
0214     Q_UNUSED(e);
0215 
0216     QPainter painter(this);
0217     const QRect gradientRect_ = gradientRect();
0218     // Gradient
0219     painter.save();
0220     paintGradient(painter, gradientRect_);
0221     painter.restore();
0222     // Border
0223     QColor borderColor = palette().text().color();
0224     borderColor.setAlpha(64);
0225     painter.setPen(borderColor);
0226     painter.drawRect(gradientRect_.adjusted(0, 0, -1, -1));
0227     // Handles
0228     const QVector<Handle> sortedHandles_ = sortedHandles();
0229     const int halfHandleWidth = handleWidth / 2;
0230     painter.save();
0231     for (const Handle &handle : sortedHandles_) {
0232         const int handleX = static_cast<int>(qRound(handle.position * static_cast<qreal>(gradientRect_.width() - 1))) + halfHandleWidth;
0233         const QRect handleRect(handleX - halfHandleWidth, gradientRect_.bottom() + 1, handleWidth, handleHeight);
0234         paintHandle(painter, handleRect, handle);
0235     }
0236     painter.restore();
0237 }
0238 
0239 void KisLevelsSlider::mousePressEvent(QMouseEvent *e)
0240 {
0241     if (m_handles.size() == 0) {
0242         return;
0243     }
0244     if (e->button() != Qt::LeftButton) {
0245         return;
0246     }
0247 
0248     qreal mousePosition = positionFromX(e->x());
0249     int handleIndex = closestHandleToPosition(mousePosition);
0250 
0251     if (handleIndex != -1) {
0252         m_selectedHandle = handleIndex;
0253         const int handleX = xFromPosition(m_handles[handleIndex].position);
0254         if (qAbs(handleX - e->x()) > handleWidth) {
0255             setHandlePosition(handleIndex, mousePosition);
0256         } else {
0257             update();
0258         }
0259     }
0260 }
0261 
0262 void KisLevelsSlider::mouseMoveEvent(QMouseEvent *e)
0263 {
0264     if (m_handles.size() == 0) {
0265         return;
0266     }
0267 
0268     if (e->buttons() & Qt::LeftButton && m_selectedHandle != -1) {
0269         setHandlePosition(m_selectedHandle, positionFromX(e->x()));
0270     } else {
0271         int handleIndex = closestHandleToX(e->x());
0272         if (handleIndex != -1) {
0273             m_hoveredHandle = handleIndex;
0274             update();
0275         }
0276     }
0277 
0278 }
0279 
0280 void KisLevelsSlider::leaveEvent(QEvent *e)
0281 {
0282     m_hoveredHandle = -1;
0283     update();
0284     QWidget::leaveEvent(e);
0285 }
0286 
0287 void KisLevelsSlider::keyPressEvent(QKeyEvent *e)
0288 {
0289     if (m_handles.size() == 0) {
0290         return;
0291     }
0292     if (m_selectedHandle == -1) {
0293         return;
0294     }
0295 
0296     switch (e->key()) {
0297     case Qt::Key_Left:
0298         handleIncrementInput(-1, e->modifiers());
0299         return;
0300     case Qt::Key_Right:
0301         handleIncrementInput(1, e->modifiers());
0302         return;
0303     default:
0304         QWidget::keyPressEvent(e);
0305     }
0306 }
0307 
0308 void KisLevelsSlider::wheelEvent(QWheelEvent *e)
0309 {
0310     if (e->angleDelta().y() != 0) {
0311         handleIncrementInput(e->angleDelta().y(), e->modifiers());
0312         e->accept();
0313     } else {
0314         QWidget::wheelEvent(e);
0315     }
0316 }
0317 
0318 
0319 KisInputLevelsSlider::KisInputLevelsSlider(QWidget *parent)
0320     : KisLevelsSlider(parent)
0321 {
0322     m_handles.resize(2);
0323     m_handles[0].index = 0;
0324     m_handles[0].position = 0.0;
0325     m_handles[0].color = Qt::black;
0326     m_handles[1].index = 1;
0327     m_handles[1].position = 1.0;
0328     m_handles[1].color = Qt::white;
0329     m_selectedHandle = 0;
0330     connect(this, &KisInputLevelsSlider::handlePositionChanged,
0331         [this](int handleIndex, qreal position)
0332         {
0333             if (handleIndex == m_handles.first().index) {
0334                 emit blackPointChanged(position);
0335             } else if (handleIndex == m_handles.last().index) {
0336                 emit whitePointChanged(position);
0337             }
0338         }
0339     );
0340 }
0341 
0342 KisInputLevelsSlider::~KisInputLevelsSlider()
0343 {}
0344 
0345 qreal KisInputLevelsSlider::blackPoint() const
0346 {
0347     return m_handles.first().position;
0348 }
0349 
0350 qreal KisInputLevelsSlider::whitePoint() const
0351 {
0352     return m_handles.last().position;
0353 }
0354 
0355 void KisInputLevelsSlider::setBlackPoint(qreal newBlackPoint)
0356 {
0357     setHandlePosition(m_handles.first().index, newBlackPoint);
0358 }
0359 
0360 void KisInputLevelsSlider::setWhitePoint(qreal newWhitePoint)
0361 {
0362     setHandlePosition(m_handles.last().index, newWhitePoint);
0363 }
0364 
0365 void KisInputLevelsSlider::reset(qreal newBlackPoint, qreal newWhitePoint)
0366 {
0367     newBlackPoint = qBound(0.0, newBlackPoint, 1.0);
0368     newWhitePoint = qBound(0.0, newWhitePoint, 1.0);
0369 
0370     if (m_constrainPositions) {
0371         if (newWhitePoint < newBlackPoint + minimumSpaceBetweenHandles) {
0372             newWhitePoint = newBlackPoint + minimumSpaceBetweenHandles;
0373             if (newWhitePoint < 1.0) {
0374                 newWhitePoint = 1.0;
0375                 newBlackPoint = 1.0 - minimumSpaceBetweenHandles;
0376             }
0377         }
0378         if (newBlackPoint <= whitePoint() - minimumSpaceBetweenHandles) {
0379             setBlackPoint(newBlackPoint);
0380             setWhitePoint(newWhitePoint);
0381         } else {
0382             setWhitePoint(newWhitePoint);
0383             setBlackPoint(newBlackPoint);
0384         }
0385     } else {
0386         setBlackPoint(newBlackPoint);
0387         setWhitePoint(newWhitePoint);
0388     }
0389 }
0390 
0391 void KisInputLevelsSlider::paintBottomGradientMiddleSection(QImage &gradientImage, const QVector<Handle> &sortedHandles_)
0392 {
0393     if (m_handles.size() < 2) {
0394         return;
0395     }
0396 
0397     const int startPos = static_cast<int>(qRound(sortedHandles_.first().position * static_cast<qreal>(gradientImage.width() - 1))) + 1;
0398     const int endPos = static_cast<int>(qRound(sortedHandles_.last().position * static_cast<qreal>(gradientImage.width() - 1))) + 1;
0399     QRgb *pixel = reinterpret_cast<QRgb*>(gradientImage.bits()) + startPos;
0400     for (int x = startPos; x < endPos; ++x, ++pixel) {
0401         const qreal t = static_cast<qreal>(x - startPos) / static_cast<qreal>(endPos - startPos);
0402         *pixel =KisPaintingTweaks::blendColors(
0403                     sortedHandles_.last().color,
0404                     sortedHandles_.first().color,
0405                     t
0406                 ).rgba();
0407     }
0408 }
0409 
0410 void KisInputLevelsSlider::paintGradient(QPainter &painter, const QRect &rect)
0411 {
0412     if (m_handles.size() == 0) {
0413         return;
0414     }
0415 
0416     painter.setRenderHint(QPainter::SmoothPixmapTransform);
0417     if (!isEnabled()) {
0418         painter.setOpacity(0.5);
0419     }
0420     QImage gradientImage(rect.width(), 1, QImage::Format_ARGB32);
0421     const int halfGradientHeight = rect.height() / 2;
0422 
0423     // Top gradient
0424     {
0425         QRgb *pixel = reinterpret_cast<QRgb*>(gradientImage.bits());
0426         for (int x = 0; x < gradientImage.width(); ++x, ++pixel) {
0427             const qreal t = static_cast<qreal>(x) / static_cast<qreal>(gradientImage.width() - 1);
0428             *pixel =KisPaintingTweaks::blendColors(m_handles.last().color, m_handles.first().color, t).rgba();
0429         }
0430     }
0431     painter.drawImage(rect.adjusted(0, 0, 0, -(halfGradientHeight + (rect.height() & 1 ? 1 : 0))), gradientImage);
0432 
0433     // Bottom gradient
0434     QVector<Handle> sortedHandles_ = sortedHandles();
0435     {
0436         const int endPos = static_cast<int>(qRound(sortedHandles_.first().position * static_cast<qreal>(gradientImage.width() - 1)) + 1);
0437         QRgb *pixel = reinterpret_cast<QRgb*>(gradientImage.bits());
0438         for (int x = 0; x < endPos; ++x, ++pixel) {
0439             *pixel = sortedHandles_.first().color.rgba();
0440         }
0441     }
0442     paintBottomGradientMiddleSection(gradientImage, sortedHandles_);
0443     {
0444         const int startPos = static_cast<int>(qRound(sortedHandles_.last().position * static_cast<qreal>(gradientImage.width() - 1)) + 1);
0445         QRgb *pixel = reinterpret_cast<QRgb*>(gradientImage.bits()) + startPos;
0446         for (int x = startPos; x < rect.width(); ++x, ++pixel) {
0447             *pixel = sortedHandles_.last().color.rgba();
0448         }
0449     }
0450     painter.drawImage(rect.adjusted(0, halfGradientHeight, 0, 0), gradientImage);
0451 }
0452 
0453 
0454 KisInputLevelsSliderWithGamma::KisInputLevelsSliderWithGamma(QWidget *parent)
0455     : KisInputLevelsSlider(parent)
0456     , m_gamma(1.0)
0457 {
0458     m_handles.last().index = 2;
0459     m_handles.insert(1, {1, 0.5, Qt::gray});
0460 }
0461 
0462 KisInputLevelsSliderWithGamma::~KisInputLevelsSliderWithGamma()
0463 {}
0464 
0465 qreal KisInputLevelsSliderWithGamma::gamma() const
0466 {
0467     return m_gamma;
0468 }
0469 
0470 void KisInputLevelsSliderWithGamma::setHandlePosition(int handleIndex, qreal newPosition)
0471 {
0472     Q_ASSERT(handleIndex >= 0 && handleIndex < m_handles.size());
0473 
0474     if (handleIndex == 1) {
0475         newPosition = qBound(m_handles.first().position, newPosition, m_handles.last().position);
0476         if (newPosition == m_handles[1].position) {
0477             return;
0478         }
0479         m_handles[1].position = newPosition;
0480         m_gamma = positionToGamma();
0481         update();
0482         emit handlePositionChanged(1, newPosition);
0483         emit gammaChanged(m_gamma);
0484     } else {
0485         if (handleIndex == m_handles.first().index) {
0486             newPosition = qBound(0.0, newPosition, m_handles.last().position - minimumSpaceBetweenHandles);
0487         } else if (handleIndex == m_handles.last().index) {
0488             newPosition = qBound(m_handles.first().position + minimumSpaceBetweenHandles, newPosition, 1.0);
0489         }
0490         if (newPosition == m_handles[handleIndex].position) {
0491             return;
0492         }
0493         m_handles[handleIndex].position = newPosition;
0494         m_handles[1].position = gammaToPosition();
0495         update();
0496         emit handlePositionChanged(handleIndex, newPosition);
0497         emit handlePositionChanged(1, newPosition);
0498     }
0499 
0500 }
0501 
0502 void KisInputLevelsSliderWithGamma::setGamma(qreal newGamma)
0503 {
0504     newGamma = qBound(0.1, newGamma, 10.0);
0505     if (newGamma == m_gamma) {
0506         return;
0507     }
0508     m_gamma = newGamma;
0509     m_handles[1].position = gammaToPosition();
0510     update();
0511     emit gammaChanged(m_gamma);
0512     emit handlePositionChanged(1, m_handles[1].position);
0513 }
0514 
0515 void KisInputLevelsSliderWithGamma::reset(qreal newBlackPoint, qreal newWhitePoint)
0516 {
0517     KisInputLevelsSlider::reset(newBlackPoint, newWhitePoint);
0518 }
0519 
0520 void KisInputLevelsSliderWithGamma::reset(qreal newBlackPoint, qreal newWhitePoint, qreal newGamma)
0521 {
0522     reset(newBlackPoint, newWhitePoint);
0523     setGamma(newGamma);
0524 }
0525 
0526 void KisInputLevelsSliderWithGamma::paintBottomGradientMiddleSection(QImage &gradientImage, const QVector<Handle> &sortedHandles_)
0527 {
0528     if (m_handles.size() < 2) {
0529         return;
0530     }
0531     if (m_handles.size() < 3) {
0532         KisInputLevelsSlider::paintBottomGradientMiddleSection(gradientImage, sortedHandles_);
0533         return;
0534     }
0535 
0536     const qreal inverseGamma = 1.0 / m_gamma;
0537     const int startPos = static_cast<int>(qRound(sortedHandles_.first().position * static_cast<qreal>(gradientImage.width() - 1)));
0538     const int endPos = static_cast<int>(qRound(sortedHandles_.last().position * static_cast<qreal>(gradientImage.width() - 1))) + 1;
0539     QRgb *pixel = reinterpret_cast<QRgb*>(gradientImage.bits()) + startPos;
0540     for (int x = startPos; x < endPos; ++x, ++pixel) {
0541         const qreal t = static_cast<qreal>(x - startPos) / static_cast<qreal>(endPos - startPos);
0542         *pixel =KisPaintingTweaks::blendColors(
0543                     sortedHandles_.last().color,
0544                     sortedHandles_.first().color,
0545                     std::pow(t, inverseGamma)
0546                 ).rgba();
0547     }
0548 }
0549 
0550 qreal KisInputLevelsSliderWithGamma::gammaToPosition() const
0551 {
0552     qreal relativePosition;
0553     const qreal log1_2 = std::log(0.5);
0554     // the function would be "relativePosition = exp(gamma * ln(1/2)" but since
0555     // we want to limit the gamma from 0.1 to 10 we map the gamma
0556     // in a way such that "exp(max_gamma * ln(1/2)) = 1" and
0557     // "exp(min_gamma * ln(1/2)) = 0"
0558     if (m_gamma > 1.0) {
0559         const qreal mappedPosition = std::exp(10.0 * log1_2);
0560         relativePosition = (std::exp(m_gamma * log1_2) - mappedPosition) / (1.0 - mappedPosition * 2.0);
0561     } else {
0562         const qreal mappedPosition = std::exp(0.1 * log1_2);
0563         relativePosition = (std::exp(m_gamma * log1_2) + mappedPosition - 1.0) / (mappedPosition * 2.0 - 1.0);
0564     }
0565     return blackPoint() + relativePosition * (whitePoint() - blackPoint());
0566 }
0567 
0568 qreal KisInputLevelsSliderWithGamma::positionToGamma() const
0569 {
0570     const qreal relativePosition = (handlePosition(1) - blackPoint()) / (whitePoint() - blackPoint());
0571     const qreal log1_2 = std::log(0.5);
0572     // the function would be "gamma = ln(relativePosition) / ln(1/2)" but since
0573     // we want to limit the gamma from 0.1 to 10 we map the relative position
0574     // in a way such that "ln(min_relativePosition) / ln(1/2) = 10" and
0575     // "ln(max_relativePosition) / ln(1/2) = 0.1"
0576     if (relativePosition < 0.5) {
0577         const qreal mappedPosition = std::exp(10.0 * log1_2);
0578         return std::log(mappedPosition + relativePosition - relativePosition * mappedPosition * 2.0) / log1_2;
0579     } else {
0580         const qreal mappedPosition = std::exp(0.1 * log1_2);
0581         return std::log(1 - (mappedPosition + relativePosition) + relativePosition * mappedPosition * 2.0) / log1_2;
0582     }
0583 }
0584 
0585 
0586 KisOutputLevelsSlider::KisOutputLevelsSlider(QWidget *parent)
0587     : KisInputLevelsSlider(parent)
0588 {
0589     m_constrainPositions = false;
0590 }
0591 
0592 KisOutputLevelsSlider::~KisOutputLevelsSlider()
0593 {}
0594 
0595 
0596 KisThresholdSlider::KisThresholdSlider(QWidget *parent)
0597     : KisInputLevelsSlider(parent)
0598 {
0599     m_constrainPositions = false;
0600 }
0601 
0602 KisThresholdSlider::~KisThresholdSlider()
0603 {}
0604 
0605 qreal KisThresholdSlider::threshold() const
0606 {
0607     return blackPoint();
0608 }
0609 
0610 void KisThresholdSlider::setHandlePosition(int handleIndex, qreal newPosition)
0611 {
0612     Q_ASSERT(handleIndex >= 0 && handleIndex < m_handles.size());
0613     reset(newPosition, newPosition);
0614 }
0615 
0616 void KisThresholdSlider::setBlackPoint(qreal newBlackPoint)
0617 {
0618     reset(newBlackPoint, newBlackPoint);
0619 }
0620 
0621 void KisThresholdSlider::setWhitePoint(qreal newWhitePoint)
0622 {
0623     reset(newWhitePoint, newWhitePoint);
0624 }
0625 
0626 void KisThresholdSlider::reset(qreal newBlackPoint, qreal newWhitePoint)
0627 {
0628     Q_UNUSED(newWhitePoint);
0629 
0630     newBlackPoint = qBound(0.0, newBlackPoint, 1.0);
0631     if (newBlackPoint == blackPoint()) {
0632         return;
0633     }
0634     m_handles.first().position = m_handles.last().position = newBlackPoint;
0635     update();
0636     emit handlePositionChanged(0, newBlackPoint);
0637     emit blackPointChanged(newBlackPoint);
0638     emit handlePositionChanged(1, newBlackPoint);
0639     emit whitePointChanged(newBlackPoint);
0640     emit thresholdChanged(newBlackPoint);
0641 }
0642 
0643 void KisThresholdSlider::setThreshold(qreal newThreshold)
0644 {
0645     reset(newThreshold, newThreshold);
0646 }
0647 
0648 void KisThresholdSlider::paintBottomGradientMiddleSection(QImage&, const QVector<Handle>&)
0649 {}
0650 
0651 void KisThresholdSlider::paintHandle(QPainter &painter, const QRect &rect, const Handle &handle)
0652 {
0653     if (handle.index != m_handles.first().index) {
0654         return;
0655     }
0656     if (m_hoveredHandle >= 0) {
0657         m_hoveredHandle = 0;
0658     }
0659     if (m_selectedHandle >= 0) {
0660         m_selectedHandle = 0;
0661     }
0662     KisLevelsSlider::paintHandle(painter, rect, handle);
0663 }