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

0001 /*
0002  *  SPDX-FileCopyrightText: 2008 Cyrille Berger <cberger@cberger.net>
0003  *  SPDX-FileCopyrightText: 2011 Sven Langkamp <sven.langkamp@gmail.com>
0004  *  SPDX-FileCopyrightText: 2015 Moritz Molch <kde@moritzmolch.de>
0005  *
0006  *  SPDX-License-Identifier: LGPL-2.0-or-later
0007  */
0008 
0009 #include "kis_color_input.h"
0010 
0011 #include <KoConfig.h>
0012 #ifdef HAVE_OPENEXR
0013 #include <half.h>
0014 #endif
0015 
0016 #include <cmath>
0017 
0018 #include <kis_debug.h>
0019 
0020 #include <QHBoxLayout>
0021 #include <QLabel>
0022 #include <QLineEdit>
0023 #include <QSpinBox>
0024 #include <QDoubleSpinBox>
0025 
0026 #include <klocalizedstring.h>
0027 
0028 #include <KoChannelInfo.h>
0029 #include <KoColor.h>
0030 #include <KoColorSlider.h>
0031 #include <KoColorSpace.h>
0032 #include <KisHsvColorSlider.h>
0033 
0034 #include "kis_double_parse_spin_box.h"
0035 #include "kis_int_parse_spin_box.h"
0036 #include "kis_signals_blocker.h"
0037 
0038 KisColorInput::KisColorInput(QWidget* parent, const KoChannelInfo* channelInfo, KoColor* color, KoColorDisplayRendererInterface *displayRenderer, bool usePercentage) :
0039     QWidget(parent), m_channelInfo(channelInfo), m_color(color), m_displayRenderer(displayRenderer),
0040     m_usePercentage(usePercentage)
0041 {
0042 }
0043 
0044 void KisColorInput::init()
0045 {
0046     QHBoxLayout* m_layout = new QHBoxLayout(this);
0047     m_layout->setContentsMargins(0,0,0,0);
0048     m_layout->setSpacing(1);
0049 
0050     QLabel* m_label = new QLabel(i18n("%1:", m_channelInfo->name()), this);
0051     m_layout->addWidget(m_label);
0052 
0053     m_colorSlider = new KoColorSlider(Qt::Horizontal, this, m_displayRenderer);
0054     m_colorSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0055     m_layout->addWidget(m_colorSlider);
0056 
0057     QWidget* m_input = createInput();
0058     m_layout->addWidget(m_input);
0059 }
0060 
0061 KisIntegerColorInput::KisIntegerColorInput(QWidget* parent, const KoChannelInfo* channelInfo, KoColor* color, KoColorDisplayRendererInterface *displayRenderer, bool usePercentage) :
0062     KisColorInput(parent, channelInfo, color, displayRenderer, usePercentage)
0063 {
0064     init();
0065 }
0066 
0067 void KisIntegerColorInput::setValue(int v)
0068 {
0069     quint8* data = m_color->data() + m_channelInfo->pos();
0070     switch (m_channelInfo->channelValueType()) {
0071     case KoChannelInfo::UINT8:
0072         *(reinterpret_cast<quint8*>(data)) = v;
0073         break;
0074     case KoChannelInfo::UINT16:
0075         *(reinterpret_cast<quint16*>(data)) = v;
0076         break;
0077     case KoChannelInfo::UINT32:
0078         *(reinterpret_cast<quint32*>(data)) = v;
0079         break;
0080     default:
0081         Q_ASSERT(false);
0082     }
0083     emit(updated());
0084 }
0085 
0086 void KisIntegerColorInput::update()
0087 {
0088     KoColor min = *m_color;
0089     KoColor max = *m_color;
0090     quint8* data = m_color->data() + m_channelInfo->pos();
0091     quint8* dataMin = min.data() + m_channelInfo->pos();
0092     quint8* dataMax = max.data() + m_channelInfo->pos();
0093     m_intNumInput->blockSignals(true);
0094     m_colorSlider->blockSignals(true);
0095     switch (m_channelInfo->channelValueType()) {
0096     case KoChannelInfo::UINT8:
0097         if (m_usePercentage) {
0098             m_intNumInput->setMaximum(100);
0099             m_intNumInput->setValue(round(*(reinterpret_cast<quint8*>(data))*1.0 / 255.0 * 100.0));
0100         } else {
0101             m_intNumInput->setMaximum(0xFF);
0102             m_intNumInput->setValue(*(reinterpret_cast<quint8*>(data)));
0103         }
0104         m_colorSlider->setValue(*(reinterpret_cast<quint8*>(data)));
0105         *(reinterpret_cast<quint8*>(dataMin)) = 0x0;
0106         *(reinterpret_cast<quint8*>(dataMax)) = 0xFF;
0107         break;
0108     case KoChannelInfo::UINT16:
0109         if (m_usePercentage) {
0110             m_intNumInput->setMaximum(100);
0111             m_intNumInput->setValue(round(*(reinterpret_cast<quint16*>(data))*1.0 / 65535.0 * 100.0));
0112         } else {
0113             m_intNumInput->setMaximum(0xFFFF);
0114             m_intNumInput->setValue(*(reinterpret_cast<quint16*>(data)));
0115         }
0116         m_colorSlider->setValue(*(reinterpret_cast<quint16*>(data)));
0117         *(reinterpret_cast<quint16*>(dataMin)) = 0x0;
0118         *(reinterpret_cast<quint16*>(dataMax)) = 0xFFFF;
0119         break;
0120     case KoChannelInfo::UINT32:
0121         if (m_usePercentage) {
0122             m_intNumInput->setMaximum(100);
0123             m_intNumInput->setValue(round(*(reinterpret_cast<quint32*>(data))*1.0 / 4294967295.0 * 100.0));
0124         } else {
0125             m_intNumInput->setMaximum(0xFFFF);
0126             m_intNumInput->setValue(*(reinterpret_cast<quint32*>(data)));
0127         }
0128         m_colorSlider->setValue(*(reinterpret_cast<quint32*>(data)));
0129         *(reinterpret_cast<quint32*>(dataMin)) = 0x0;
0130         *(reinterpret_cast<quint32*>(dataMax)) = 0xFFFFFFFF;
0131         break;
0132     default:
0133         Q_ASSERT(false);
0134     }
0135     m_colorSlider->setColors(min, max);
0136     m_intNumInput->blockSignals(false);
0137     m_colorSlider->blockSignals(false);
0138 }
0139 
0140 QWidget* KisIntegerColorInput::createInput()
0141 {
0142     m_intNumInput = new KisIntParseSpinBox(this);
0143     m_intNumInput->setMinimum(0);
0144     m_colorSlider->setMinimum(0);
0145 
0146     if (m_usePercentage) {
0147         m_intNumInput->setSuffix(i18n("%"));
0148     } else {
0149         m_intNumInput->setSuffix("");
0150     }
0151 
0152     switch (m_channelInfo->channelValueType()) {
0153     case KoChannelInfo::UINT8:
0154         if (m_usePercentage) {
0155             m_intNumInput->setMaximum(100);
0156         } else {
0157             m_intNumInput->setMaximum(0xFF);
0158         }
0159         m_colorSlider->setMaximum(0xFF);
0160         break;
0161     case KoChannelInfo::UINT16:
0162         if (m_usePercentage) {
0163             m_intNumInput->setMaximum(100);
0164         } else {
0165             m_intNumInput->setMaximum(0xFFFF);
0166         }
0167         m_colorSlider->setMaximum(0xFFFF);
0168         break;
0169     case KoChannelInfo::UINT32:
0170         if (m_usePercentage) {
0171             m_intNumInput->setMaximum(100);
0172         } else {
0173             m_intNumInput->setMaximum(0xFFFFFFFF);
0174         }
0175         m_colorSlider->setMaximum(0xFFFFFFFF);
0176         break;
0177     default:
0178         Q_ASSERT(false);
0179     }
0180     connect(m_colorSlider, SIGNAL(valueChanged(int)), this, SLOT(onColorSliderChanged(int)));
0181     connect(m_intNumInput, SIGNAL(valueChanged(int)), this, SLOT(onNumInputChanged(int)));
0182     return m_intNumInput;
0183 }
0184 
0185 void KisIntegerColorInput::setPercentageWise(bool val)
0186 {
0187     m_usePercentage = val;
0188 
0189     if (m_usePercentage) {
0190         m_intNumInput->setSuffix(i18n("%"));
0191     } else {
0192         m_intNumInput->setSuffix("");
0193     }
0194 }
0195 
0196 void KisIntegerColorInput::onColorSliderChanged(int val)
0197 {
0198     m_intNumInput->blockSignals(true);
0199     if (m_usePercentage) {
0200         switch (m_channelInfo->channelValueType()) {
0201         case KoChannelInfo::UINT8:
0202             m_intNumInput->setValue(round((val*1.0) / 255.0 * 100.0));
0203             break;
0204         case KoChannelInfo::UINT16:
0205             m_intNumInput->setValue(round((val*1.0) / 65535.0 * 100.0));
0206             break;
0207         case KoChannelInfo::UINT32:
0208             m_intNumInput->setValue(round((val*1.0) / 4294967295.0 * 100.0));
0209             break;
0210         default:
0211             Q_ASSERT(false);
0212         }
0213     } else {
0214         m_intNumInput->setValue(val);
0215     }
0216     m_intNumInput->blockSignals(false);
0217     setValue(val);
0218 }
0219 
0220 void KisIntegerColorInput::onNumInputChanged(int val)
0221 {
0222     m_colorSlider->blockSignals(true);
0223     if (m_usePercentage) {
0224         switch (m_channelInfo->channelValueType()) {
0225         case KoChannelInfo::UINT8:
0226             m_colorSlider->setValue((val*1.0)/100.0 * 255.0);
0227             m_colorSlider->blockSignals(false);
0228             setValue((val*1.0)/100.0 * 255.0);
0229             break;
0230         case KoChannelInfo::UINT16:
0231             m_colorSlider->setValue((val*1.0)/100.0 * 65535.0);
0232             m_colorSlider->blockSignals(false);
0233             setValue((val*1.0)/100.0 * 65535.0);
0234             break;
0235         case KoChannelInfo::UINT32:
0236             m_colorSlider->setValue((val*1.0)/100.0 * 4294967295.0);
0237             m_colorSlider->blockSignals(false);
0238             setValue((val*1.0)/100.0 * 4294967295.0);
0239             break;
0240         default:
0241             Q_ASSERT(false);
0242         }
0243     } else {
0244         m_colorSlider->setValue(val);
0245         m_colorSlider->blockSignals(false);
0246         setValue(val);
0247     }
0248 }
0249 
0250 KisFloatColorInput::KisFloatColorInput(QWidget* parent, const KoChannelInfo* channelInfo, KoColor* color, KoColorDisplayRendererInterface *displayRenderer, bool usePercentage) :
0251     KisColorInput(parent, channelInfo, color, displayRenderer, usePercentage)
0252 {
0253     init();
0254 }
0255 
0256 void KisFloatColorInput::setValue(double v)
0257 {
0258     quint8* data = m_color->data() + m_channelInfo->pos();
0259     switch (m_channelInfo->channelValueType()) {
0260 #ifdef HAVE_OPENEXR
0261     case KoChannelInfo::FLOAT16:
0262         *(reinterpret_cast<half*>(data)) = v;
0263         break;
0264 #endif
0265     case KoChannelInfo::FLOAT32:
0266         *(reinterpret_cast<float*>(data)) = v;
0267         break;
0268     default:
0269         Q_ASSERT(false);
0270     }
0271     emit(updated());
0272 }
0273 
0274 QWidget* KisFloatColorInput::createInput()
0275 {
0276     m_dblNumInput = new KisDoubleParseSpinBox(this);
0277     m_dblNumInput->setMinimum(0);
0278     m_dblNumInput->setMaximum(1.0);
0279     connect(m_colorSlider, SIGNAL(valueChanged(int)), this, SLOT(sliderChanged(int)));
0280     connect(m_dblNumInput, SIGNAL(valueChanged(double)), this, SLOT(setValue(double)));
0281     m_dblNumInput->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
0282     m_dblNumInput->setMinimumWidth(60);
0283     m_dblNumInput->setMaximumWidth(60);
0284     
0285     quint8* data = m_color->data() + m_channelInfo->pos();
0286     qreal value = 1.0;
0287 
0288     switch (m_channelInfo->channelValueType()) {
0289 #ifdef HAVE_OPENEXR
0290     case KoChannelInfo::FLOAT16:
0291         value = *(reinterpret_cast<half*>(data));
0292         break;
0293 #endif
0294     case KoChannelInfo::FLOAT32:
0295         value = *(reinterpret_cast<float*>(data));
0296         break;
0297     default:
0298         Q_ASSERT(false);
0299     }
0300     m_dblNumInput->setValue(value);
0301 
0302     return m_dblNumInput;
0303 }
0304 
0305 void KisFloatColorInput::sliderChanged(int i)
0306 {
0307     const qreal floatRange = m_maxValue - m_minValue;
0308     m_dblNumInput->setValue(m_minValue + (i / 255.0) * floatRange);
0309 }
0310 
0311 void KisFloatColorInput::update()
0312 {
0313     KoColor min = *m_color;
0314     KoColor max = *m_color;
0315     quint8* data = m_color->data() + m_channelInfo->pos();
0316     quint8* dataMin = min.data() + m_channelInfo->pos();
0317     quint8* dataMax = max.data() + m_channelInfo->pos();
0318 
0319     qreal value = 1.0;
0320     m_minValue = m_displayRenderer->minVisibleFloatValue(m_channelInfo);
0321     m_maxValue = m_displayRenderer->maxVisibleFloatValue(m_channelInfo);
0322     m_dblNumInput->blockSignals(true);
0323     m_colorSlider->blockSignals(true);
0324 
0325     switch (m_channelInfo->channelValueType()) {
0326 #ifdef HAVE_OPENEXR
0327     case KoChannelInfo::FLOAT16:
0328         value = *(reinterpret_cast<half*>(data));
0329         m_minValue = qMin(value, m_minValue);
0330         m_maxValue = qMax(value, m_maxValue);
0331         *(reinterpret_cast<half*>(dataMin)) = m_minValue;
0332         *(reinterpret_cast<half*>(dataMax)) = m_maxValue;
0333         break;
0334 #endif
0335     case KoChannelInfo::FLOAT32:
0336         value = *(reinterpret_cast<float*>(data));
0337         m_minValue = qMin(value, m_minValue);
0338         m_maxValue = qMax(value, m_maxValue);
0339         *(reinterpret_cast<float*>(dataMin)) = m_minValue;
0340         *(reinterpret_cast<float*>(dataMax)) = m_maxValue;
0341         break;
0342     default:
0343         Q_ASSERT(false);
0344     }
0345 
0346     m_dblNumInput->setMinimum(m_minValue);
0347     m_dblNumInput->setMaximum(m_maxValue);
0348 
0349     // ensure at least 3 significant digits are always shown
0350     int newPrecision = 2 + qMax(qreal(0.0), std::ceil(-std::log10(m_maxValue)));
0351     if (newPrecision != m_dblNumInput->decimals()) {
0352         m_dblNumInput->setDecimals(newPrecision);
0353         m_dblNumInput->updateGeometry();
0354     }
0355     m_dblNumInput->setValue(value);
0356 
0357     m_colorSlider->setColors(min, max);
0358 
0359     const qreal floatRange = m_maxValue - m_minValue;
0360     m_colorSlider->setValue((value - m_minValue) / floatRange * 255);
0361     m_dblNumInput->blockSignals(false);
0362     m_colorSlider->blockSignals(false);
0363 }
0364 
0365 KisHexColorInput::KisHexColorInput(QWidget* parent, KoColor* color, KoColorDisplayRendererInterface *displayRenderer, bool usePercentage, bool usePreview) :
0366     KisColorInput(parent, 0, color, displayRenderer, usePercentage)
0367 {
0368     QHBoxLayout* m_layout = new QHBoxLayout(this);
0369     m_layout->setContentsMargins(0,0,0,0);
0370     m_layout->setSpacing(1);
0371 
0372     QLabel* m_label = new QLabel(i18n("Color name:"), this);
0373     m_label->setMinimumWidth(50);
0374     m_layout->addWidget(m_label);
0375 
0376     QWidget* m_input = createInput();
0377     m_input->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
0378 
0379     if(usePreview) {
0380         m_colorPreview = new QLabel("");
0381         m_colorPreview->setMinimumWidth(30);
0382         m_layout->addWidget(m_colorPreview);
0383     }
0384 
0385     m_layout->addWidget(m_input);
0386 }
0387 
0388 void KisHexColorInput::setValue()
0389 {
0390     QString valueString = m_hexInput->text();
0391     valueString.remove(QChar('#'));
0392 
0393     QList<KoChannelInfo*> channels = m_color->colorSpace()->channels();
0394     channels = KoChannelInfo::displayOrderSorted(channels);
0395     Q_FOREACH (KoChannelInfo* channel, channels) {
0396         if (channel->channelType() == KoChannelInfo::COLOR) {
0397             Q_ASSERT(channel->channelValueType() == KoChannelInfo::UINT8);
0398             quint8* data = m_color->data() + channel->pos();
0399 
0400             int value = valueString.left(2).toInt(0, 16);
0401             *(reinterpret_cast<quint8*>(data)) = value;
0402             valueString.remove(0, 2);
0403         }
0404     }
0405     emit(updated());
0406 }
0407 
0408 void KisHexColorInput::update()
0409 {
0410     QString hexString("#");
0411 
0412     QList<KoChannelInfo*> channels = m_color->colorSpace()->channels();
0413     channels = KoChannelInfo::displayOrderSorted(channels);
0414     Q_FOREACH (KoChannelInfo* channel, channels) {
0415         if (channel->channelType() == KoChannelInfo::COLOR) {
0416             Q_ASSERT(channel->channelValueType() == KoChannelInfo::UINT8);
0417             quint8* data = m_color->data() + channel->pos();
0418             hexString.append(QString("%1").arg(*(reinterpret_cast<quint8*>(data)), 2, 16, QChar('0')));
0419         }
0420     }
0421     m_hexInput->setText(hexString);
0422     if( m_colorPreview) {
0423         m_colorPreview->setStyleSheet(QString("background-color: %1").arg(m_displayRenderer->toQColor(*m_color).name()));
0424     }
0425 }
0426 
0427 QWidget* KisHexColorInput::createInput()
0428 {
0429     m_hexInput = new QLineEdit(this);
0430     m_hexInput->setAlignment(Qt::AlignRight);
0431 
0432     int digits = 2*m_color->colorSpace()->colorChannelCount();
0433     QString pattern = QString("#?[a-fA-F0-9]{%1,%2}").arg(digits).arg(digits);
0434     m_hexInput->setValidator(new QRegExpValidator(QRegExp(pattern), this));
0435     connect(m_hexInput, SIGNAL(editingFinished()), this, SLOT(setValue()));
0436     return m_hexInput;
0437 }
0438 
0439 
0440 KisHsvColorInput::KisHsvColorInput(QWidget *parent, KoColor *color)
0441     : QWidget(parent)
0442     , m_color(color)
0443     , m_hSlider(nullptr)
0444     , m_sSlider(nullptr)
0445     , m_vSlider(nullptr)
0446     , m_hInput(nullptr)
0447     , m_sInput(nullptr)
0448     , m_vInput(nullptr)
0449     , m_h(0)
0450     , m_s(0)
0451     , m_v(0)
0452 {
0453 
0454     QLabel *labels[3];
0455     KisHsvColorSlider *sliders[3];
0456     KisDoubleParseSpinBox *inputs[3];
0457     const char *labelNames[3] = { "H:", "S:", "V:" };
0458     qreal maxValues[3] = { 360, 100, 100 };
0459     int labelWidth = 0;
0460 
0461     QVBoxLayout *mainLayout = new QVBoxLayout(this);
0462     mainLayout->setContentsMargins(0,0,0,0);
0463 
0464     for (int i = 0; i < 3; i++) {
0465         // Slider layout
0466         QHBoxLayout *sliderLayout = new QHBoxLayout();
0467         sliderLayout->setContentsMargins(0,0,0,0);
0468         sliderLayout->setSpacing(1);
0469 
0470         // Label
0471         QLabel *label = new QLabel(i18n(labelNames[i]), this);
0472         sliderLayout->addWidget(label);
0473 
0474         // Slider itself
0475         KisHsvColorSlider *slider = new KisHsvColorSlider(Qt::Horizontal, this);
0476         slider->setMinimum(0);
0477         slider->setMaximum(maxValues[i]);
0478         slider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed);
0479         sliderLayout->addWidget(slider);
0480 
0481         // Input box
0482         KisDoubleParseSpinBox *input = new KisDoubleParseSpinBox(this);
0483         input->setMinimum(0);
0484         input->setMaximum(maxValues[i]);
0485 
0486         input->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred);
0487         input->setMinimumWidth(60);
0488         input->setMaximumWidth(60);
0489 
0490         slider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
0491         sliderLayout->addWidget(input);
0492 
0493         mainLayout->addLayout(sliderLayout);
0494 
0495         // Record max label width
0496         labelWidth = qMax(labelWidth, label->sizeHint().width());
0497 
0498         sliders[i] = slider;
0499         inputs[i] = input;
0500         labels[i] = label;
0501     }
0502 
0503     // Align the labels
0504     for (int i = 0; i < 3; i++) {
0505         labels[i]->setMinimumWidth(labelWidth);
0506     }
0507 
0508     // Connect slots
0509     connect(sliders[0], SIGNAL(valueChanged(int)), this, SLOT(hueSliderChanged(int)));
0510     connect(inputs[0], SIGNAL(valueChanged(double)), this, SLOT(setHue(double)));
0511     connect(sliders[1], SIGNAL(valueChanged(int)), this, SLOT(saturationSliderChanged(int)));
0512     connect(inputs[1], SIGNAL(valueChanged(double)), this, SLOT(setSaturation(double)));
0513     connect(sliders[2], SIGNAL(valueChanged(int)), this, SLOT(valueSliderChanged(int)));
0514     connect(inputs[2], SIGNAL(valueChanged(double)), this, SLOT(setValue(double)));
0515 
0516     m_hSlider = sliders[0];
0517     m_sSlider = sliders[1];
0518     m_vSlider = sliders[2];
0519 
0520     m_hInput = inputs[0];
0521     m_sInput = inputs[1];
0522     m_vInput = inputs[2];
0523 
0524     // Set initial values
0525     QColor c = m_color->toQColor();
0526     c.getHsvF(&m_h, &m_s, &m_v);
0527     m_hInput->setValue(m_h);
0528     m_sInput->setValue(m_s);
0529     m_vInput->setValue(m_v);
0530 
0531     // Update sliders
0532     QColor minC, maxC;
0533     minC.setHsvF(0, 1, 1);
0534     maxC.setHsvF(1, 1, 1);
0535     m_hSlider->setColors(minC, maxC);
0536     m_hSlider->setCircularHue(true);
0537 
0538     recolorSliders();
0539 }
0540 
0541 void KisHsvColorInput::sendUpdate()
0542 {
0543     {
0544         KisSignalsBlocker blocker(
0545             m_hSlider, m_sSlider, m_vSlider
0546         );
0547         m_hSlider->setValue(m_h * 360);
0548         m_sSlider->setValue(m_s * 100);
0549         m_vSlider->setValue(m_v * 100);
0550     }
0551 
0552     recolorSliders();
0553 
0554     QColor c;
0555     c.setHsvF(m_h, m_s, m_v);
0556 
0557     m_color->fromQColor(c);
0558     emit(updated());
0559 }
0560 
0561 void KisHsvColorInput::setHue(double x)
0562 {
0563     if (x < 0) {
0564         x = 0;
0565     }
0566 
0567     if (x > 360) {
0568         x = 360;
0569     }
0570 
0571     m_h = x / 360;
0572     sendUpdate();
0573 }
0574 
0575 void KisHsvColorInput::setSaturation(double x)
0576 {
0577     if (x < 0) {
0578         x = 0;
0579     }
0580 
0581     if (x > 100) {
0582         x = 100;
0583     }
0584 
0585     m_s = x / 100;
0586     sendUpdate();
0587 }
0588 
0589 void KisHsvColorInput::setValue(double x)
0590 {
0591     if (x < 0) {
0592         x = 0;
0593     }
0594 
0595     if (x > 100) {
0596         x = 100;
0597     }
0598 
0599     m_v = x / 100;
0600     sendUpdate();
0601 }
0602 
0603 void KisHsvColorInput::hueSliderChanged(int i)
0604 {
0605     m_hInput->setValue(i);
0606 }
0607 
0608 void KisHsvColorInput::saturationSliderChanged(int i)
0609 {
0610     m_sInput->setValue(i);
0611 }
0612 
0613 void KisHsvColorInput::valueSliderChanged(int i)
0614 {
0615     m_vInput->setValue(i);
0616 }
0617 
0618 void KisHsvColorInput::recolorSliders() {
0619     // Update sliders
0620     QColor minC, maxC;
0621     minC.setHsvF(m_h, 0, m_v);
0622     maxC.setHsvF(m_h, 1, m_v);
0623     m_sSlider->setColors(minC, maxC);
0624 
0625     minC.setHsvF(m_h, m_s, 0);
0626     maxC.setHsvF(m_h, m_s, 1);
0627     m_vSlider->setColors(minC, maxC);
0628 }
0629 
0630 void KisHsvColorInput::update()
0631 {
0632     KisSignalsBlocker blocker(
0633         m_hInput, m_sInput, m_vInput,
0634         m_hSlider, m_sSlider, m_vSlider
0635     );
0636 
0637     // Check if it is the same color we have
0638     QColor current;
0639     current.setHsvF(m_h, m_s, m_v);
0640     QColor theirs = m_color->toQColor();
0641 
0642     // Truncate to integer for this check
0643     if (!(current.red() == theirs.red() && current.green() == theirs.green() && current.blue() == theirs.blue())) {
0644         // Apply the update
0645         qreal theirH;
0646         theirs.getHsvF(&theirH, &m_s, &m_v);
0647 
0648         // Don't jump the Hue slider around to 0 if it is currently on 360
0649         const qreal EPSILON = 1e-6;
0650         if (!((1.0 - m_h) < EPSILON && (theirH - 0.0) < EPSILON)) {
0651             m_h = theirH;
0652         }
0653 
0654         m_hInput->setValue(m_h * 360);
0655         m_sInput->setValue(m_s * 100);
0656         m_vInput->setValue(m_v * 100);
0657 
0658         recolorSliders();
0659 
0660         // Update slider positions
0661         m_hSlider->setValue(m_h * 360);
0662         m_sSlider->setValue(m_s * 100);
0663         m_vSlider->setValue(m_v * 100);
0664     }
0665 }