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 }