File indexing completed on 2024-05-19 04:29:24
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 #include <KoColorConversions.h> 0034 #include <KisSpinBoxI18nHelper.h> 0035 0036 #include "kis_double_parse_spin_box.h" 0037 #include "kis_int_parse_spin_box.h" 0038 #include "kis_signals_blocker.h" 0039 0040 KisColorInput::KisColorInput(QWidget* parent, const KoChannelInfo* channelInfo, KoColor* color, KoColorDisplayRendererInterface *displayRenderer, bool usePercentage) : 0041 QWidget(parent), m_channelInfo(channelInfo), m_color(color), m_displayRenderer(displayRenderer), 0042 m_usePercentage(usePercentage) 0043 { 0044 } 0045 0046 void KisColorInput::init() 0047 { 0048 QHBoxLayout* m_layout = new QHBoxLayout(this); 0049 m_layout->setContentsMargins(0,0,0,0); 0050 m_layout->setSpacing(1); 0051 0052 QLabel* m_label = new QLabel(i18n("%1:", m_channelInfo->name()), this); 0053 m_layout->addWidget(m_label); 0054 0055 m_colorSlider = new KoColorSlider(Qt::Horizontal, this, m_displayRenderer); 0056 m_colorSlider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 0057 m_layout->addWidget(m_colorSlider); 0058 0059 QWidget* m_input = createInput(); 0060 m_layout->addWidget(m_input); 0061 } 0062 0063 KisIntegerColorInput::KisIntegerColorInput(QWidget* parent, const KoChannelInfo* channelInfo, KoColor* color, KoColorDisplayRendererInterface *displayRenderer, bool usePercentage) : 0064 KisColorInput(parent, channelInfo, color, displayRenderer, usePercentage) 0065 { 0066 init(); 0067 } 0068 0069 void KisIntegerColorInput::setValue(int v) 0070 { 0071 quint8* data = m_color->data() + m_channelInfo->pos(); 0072 switch (m_channelInfo->channelValueType()) { 0073 case KoChannelInfo::UINT8: 0074 *(reinterpret_cast<quint8*>(data)) = v; 0075 break; 0076 case KoChannelInfo::UINT16: 0077 *(reinterpret_cast<quint16*>(data)) = v; 0078 break; 0079 case KoChannelInfo::UINT32: 0080 *(reinterpret_cast<quint32*>(data)) = v; 0081 break; 0082 default: 0083 Q_ASSERT(false); 0084 } 0085 emit(updated()); 0086 } 0087 0088 void KisIntegerColorInput::update() 0089 { 0090 KoColor min = *m_color; 0091 KoColor max = *m_color; 0092 quint8* data = m_color->data() + m_channelInfo->pos(); 0093 quint8* dataMin = min.data() + m_channelInfo->pos(); 0094 quint8* dataMax = max.data() + m_channelInfo->pos(); 0095 m_intNumInput->blockSignals(true); 0096 m_colorSlider->blockSignals(true); 0097 switch (m_channelInfo->channelValueType()) { 0098 case KoChannelInfo::UINT8: 0099 if (m_usePercentage) { 0100 m_intNumInput->setMaximum(100); 0101 m_intNumInput->setValue(round(*(reinterpret_cast<quint8*>(data))*1.0 / 255.0 * 100.0)); 0102 } else { 0103 m_intNumInput->setMaximum(0xFF); 0104 m_intNumInput->setValue(*(reinterpret_cast<quint8*>(data))); 0105 } 0106 m_colorSlider->setValue(*(reinterpret_cast<quint8*>(data))); 0107 *(reinterpret_cast<quint8*>(dataMin)) = 0x0; 0108 *(reinterpret_cast<quint8*>(dataMax)) = 0xFF; 0109 break; 0110 case KoChannelInfo::UINT16: 0111 if (m_usePercentage) { 0112 m_intNumInput->setMaximum(100); 0113 m_intNumInput->setValue(round(*(reinterpret_cast<quint16*>(data))*1.0 / 65535.0 * 100.0)); 0114 } else { 0115 m_intNumInput->setMaximum(0xFFFF); 0116 m_intNumInput->setValue(*(reinterpret_cast<quint16*>(data))); 0117 } 0118 m_colorSlider->setValue(*(reinterpret_cast<quint16*>(data))); 0119 *(reinterpret_cast<quint16*>(dataMin)) = 0x0; 0120 *(reinterpret_cast<quint16*>(dataMax)) = 0xFFFF; 0121 break; 0122 case KoChannelInfo::UINT32: 0123 if (m_usePercentage) { 0124 m_intNumInput->setMaximum(100); 0125 m_intNumInput->setValue(round(*(reinterpret_cast<quint32*>(data))*1.0 / 4294967295.0 * 100.0)); 0126 } else { 0127 m_intNumInput->setMaximum(0xFFFF); 0128 m_intNumInput->setValue(*(reinterpret_cast<quint32*>(data))); 0129 } 0130 m_colorSlider->setValue(*(reinterpret_cast<quint32*>(data))); 0131 *(reinterpret_cast<quint32*>(dataMin)) = 0x0; 0132 *(reinterpret_cast<quint32*>(dataMax)) = 0xFFFFFFFF; 0133 break; 0134 default: 0135 Q_ASSERT(false); 0136 } 0137 m_colorSlider->setColors(min, max); 0138 m_intNumInput->blockSignals(false); 0139 m_colorSlider->blockSignals(false); 0140 } 0141 0142 QWidget* KisIntegerColorInput::createInput() 0143 { 0144 m_intNumInput = new KisIntParseSpinBox(this); 0145 m_intNumInput->setMinimum(0); 0146 m_colorSlider->setMinimum(0); 0147 0148 if (m_usePercentage) { 0149 KisSpinBoxI18nHelper::setText(m_intNumInput, i18nc("{n} is the number value, % is the percent sign", "{n}%")); 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 KisSpinBoxI18nHelper::setText(m_intNumInput, i18nc("{n} is the number value, % is the percent sign", "{n}%")); 0191 } else { 0192 m_intNumInput->setPrefix(""); 0193 m_intNumInput->setSuffix(""); 0194 } 0195 } 0196 0197 void KisIntegerColorInput::onColorSliderChanged(int val) 0198 { 0199 m_intNumInput->blockSignals(true); 0200 if (m_usePercentage) { 0201 switch (m_channelInfo->channelValueType()) { 0202 case KoChannelInfo::UINT8: 0203 m_intNumInput->setValue(round((val*1.0) / 255.0 * 100.0)); 0204 break; 0205 case KoChannelInfo::UINT16: 0206 m_intNumInput->setValue(round((val*1.0) / 65535.0 * 100.0)); 0207 break; 0208 case KoChannelInfo::UINT32: 0209 m_intNumInput->setValue(round((val*1.0) / 4294967295.0 * 100.0)); 0210 break; 0211 default: 0212 Q_ASSERT(false); 0213 } 0214 } else { 0215 m_intNumInput->setValue(val); 0216 } 0217 m_intNumInput->blockSignals(false); 0218 setValue(val); 0219 } 0220 0221 void KisIntegerColorInput::onNumInputChanged(int val) 0222 { 0223 m_colorSlider->blockSignals(true); 0224 if (m_usePercentage) { 0225 switch (m_channelInfo->channelValueType()) { 0226 case KoChannelInfo::UINT8: 0227 m_colorSlider->setValue((val*1.0)/100.0 * 255.0); 0228 m_colorSlider->blockSignals(false); 0229 setValue((val*1.0)/100.0 * 255.0); 0230 break; 0231 case KoChannelInfo::UINT16: 0232 m_colorSlider->setValue((val*1.0)/100.0 * 65535.0); 0233 m_colorSlider->blockSignals(false); 0234 setValue((val*1.0)/100.0 * 65535.0); 0235 break; 0236 case KoChannelInfo::UINT32: 0237 m_colorSlider->setValue((val*1.0)/100.0 * 4294967295.0); 0238 m_colorSlider->blockSignals(false); 0239 setValue((val*1.0)/100.0 * 4294967295.0); 0240 break; 0241 default: 0242 Q_ASSERT(false); 0243 } 0244 } else { 0245 m_colorSlider->setValue(val); 0246 m_colorSlider->blockSignals(false); 0247 setValue(val); 0248 } 0249 } 0250 0251 KisFloatColorInput::KisFloatColorInput(QWidget* parent, const KoChannelInfo* channelInfo, KoColor* color, KoColorDisplayRendererInterface *displayRenderer, bool usePercentage) : 0252 KisColorInput(parent, channelInfo, color, displayRenderer, usePercentage) 0253 { 0254 init(); 0255 } 0256 0257 void KisFloatColorInput::setValue(double v) 0258 { 0259 quint8* data = m_color->data() + m_channelInfo->pos(); 0260 switch (m_channelInfo->channelValueType()) { 0261 #ifdef HAVE_OPENEXR 0262 case KoChannelInfo::FLOAT16: 0263 *(reinterpret_cast<half*>(data)) = v; 0264 break; 0265 #endif 0266 case KoChannelInfo::FLOAT32: 0267 *(reinterpret_cast<float*>(data)) = v; 0268 break; 0269 default: 0270 Q_ASSERT(false); 0271 } 0272 emit(updated()); 0273 } 0274 0275 QWidget* KisFloatColorInput::createInput() 0276 { 0277 m_dblNumInput = new KisDoubleParseSpinBox(this); 0278 m_dblNumInput->setMinimum(0); 0279 m_dblNumInput->setMaximum(1.0); 0280 connect(m_colorSlider, SIGNAL(valueChanged(int)), this, SLOT(sliderChanged(int))); 0281 connect(m_dblNumInput, SIGNAL(valueChanged(double)), this, SLOT(setValue(double))); 0282 m_dblNumInput->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); 0283 m_dblNumInput->setMinimumWidth(60); 0284 m_dblNumInput->setMaximumWidth(60); 0285 0286 quint8* data = m_color->data() + m_channelInfo->pos(); 0287 qreal value = 1.0; 0288 0289 switch (m_channelInfo->channelValueType()) { 0290 #ifdef HAVE_OPENEXR 0291 case KoChannelInfo::FLOAT16: 0292 value = *(reinterpret_cast<half*>(data)); 0293 break; 0294 #endif 0295 case KoChannelInfo::FLOAT32: 0296 value = *(reinterpret_cast<float*>(data)); 0297 break; 0298 default: 0299 Q_ASSERT(false); 0300 } 0301 m_dblNumInput->setValue(value); 0302 0303 return m_dblNumInput; 0304 } 0305 0306 void KisFloatColorInput::sliderChanged(int i) 0307 { 0308 const qreal floatRange = m_maxValue - m_minValue; 0309 m_dblNumInput->setValue(m_minValue + (i / 255.0) * floatRange); 0310 } 0311 0312 void KisFloatColorInput::update() 0313 { 0314 KoColor min = *m_color; 0315 KoColor max = *m_color; 0316 quint8* data = m_color->data() + m_channelInfo->pos(); 0317 quint8* dataMin = min.data() + m_channelInfo->pos(); 0318 quint8* dataMax = max.data() + m_channelInfo->pos(); 0319 0320 qreal value = 1.0; 0321 m_minValue = m_displayRenderer->minVisibleFloatValue(m_channelInfo); 0322 m_maxValue = m_displayRenderer->maxVisibleFloatValue(m_channelInfo); 0323 m_dblNumInput->blockSignals(true); 0324 m_colorSlider->blockSignals(true); 0325 0326 switch (m_channelInfo->channelValueType()) { 0327 #ifdef HAVE_OPENEXR 0328 case KoChannelInfo::FLOAT16: 0329 value = *(reinterpret_cast<half*>(data)); 0330 m_minValue = qMin(value, m_minValue); 0331 m_maxValue = qMax(value, m_maxValue); 0332 *(reinterpret_cast<half*>(dataMin)) = m_minValue; 0333 *(reinterpret_cast<half*>(dataMax)) = m_maxValue; 0334 break; 0335 #endif 0336 case KoChannelInfo::FLOAT32: 0337 value = *(reinterpret_cast<float*>(data)); 0338 m_minValue = qMin(value, m_minValue); 0339 m_maxValue = qMax(value, m_maxValue); 0340 *(reinterpret_cast<float*>(dataMin)) = m_minValue; 0341 *(reinterpret_cast<float*>(dataMax)) = m_maxValue; 0342 break; 0343 default: 0344 Q_ASSERT(false); 0345 } 0346 0347 m_dblNumInput->setMinimum(m_minValue); 0348 m_dblNumInput->setMaximum(m_maxValue); 0349 0350 // ensure at least 3 significant digits are always shown 0351 int newPrecision = 2 + qMax(qreal(0.0), std::ceil(-std::log10(m_maxValue))); 0352 if (newPrecision != m_dblNumInput->decimals()) { 0353 m_dblNumInput->setDecimals(newPrecision); 0354 m_dblNumInput->updateGeometry(); 0355 } 0356 m_dblNumInput->setValue(value); 0357 0358 m_colorSlider->setColors(min, max); 0359 0360 const qreal floatRange = m_maxValue - m_minValue; 0361 m_colorSlider->setValue((value - m_minValue) / floatRange * 255); 0362 m_dblNumInput->blockSignals(false); 0363 m_colorSlider->blockSignals(false); 0364 } 0365 0366 KisHexColorInput::KisHexColorInput(QWidget* parent, KoColor* color, KoColorDisplayRendererInterface *displayRenderer, bool usePercentage, bool usePreview) : 0367 KisColorInput(parent, 0, color, displayRenderer, usePercentage) 0368 { 0369 QHBoxLayout* m_layout = new QHBoxLayout(this); 0370 m_layout->setContentsMargins(0,0,0,0); 0371 m_layout->setSpacing(1); 0372 0373 QLabel* m_label = new QLabel(i18n("Color name:"), this); 0374 m_label->setMinimumWidth(50); 0375 m_layout->addWidget(m_label); 0376 0377 QWidget* m_input = createInput(); 0378 m_input->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); 0379 0380 if(usePreview) { 0381 m_colorPreview = new QLabel(""); 0382 m_colorPreview->setMinimumWidth(30); 0383 m_layout->addWidget(m_colorPreview); 0384 } 0385 0386 m_layout->addWidget(m_input); 0387 } 0388 0389 void KisHexColorInput::setValue() 0390 { 0391 QString valueString = m_hexInput->text(); 0392 valueString.remove(QChar('#')); 0393 0394 QList<KoChannelInfo*> channels = m_color->colorSpace()->channels(); 0395 channels = KoChannelInfo::displayOrderSorted(channels); 0396 Q_FOREACH (KoChannelInfo* channel, channels) { 0397 if (channel->channelType() == KoChannelInfo::COLOR) { 0398 Q_ASSERT(channel->channelValueType() == KoChannelInfo::UINT8); 0399 quint8* data = m_color->data() + channel->pos(); 0400 0401 int value = valueString.left(2).toInt(0, 16); 0402 *(reinterpret_cast<quint8*>(data)) = value; 0403 valueString.remove(0, 2); 0404 } 0405 } 0406 emit(updated()); 0407 } 0408 0409 void KisHexColorInput::update() 0410 { 0411 QString hexString("#"); 0412 0413 QList<KoChannelInfo*> channels = m_color->colorSpace()->channels(); 0414 channels = KoChannelInfo::displayOrderSorted(channels); 0415 Q_FOREACH (KoChannelInfo* channel, channels) { 0416 if (channel->channelType() == KoChannelInfo::COLOR) { 0417 Q_ASSERT(channel->channelValueType() == KoChannelInfo::UINT8); 0418 quint8* data = m_color->data() + channel->pos(); 0419 hexString.append(QString("%1").arg(*(reinterpret_cast<quint8*>(data)), 2, 16, QChar('0'))); 0420 } 0421 } 0422 m_hexInput->setText(hexString); 0423 if( m_colorPreview) { 0424 m_colorPreview->setStyleSheet(QString("background-color: %1").arg(m_displayRenderer->toQColor(*m_color).name())); 0425 } 0426 } 0427 0428 QWidget* KisHexColorInput::createInput() 0429 { 0430 m_hexInput = new QLineEdit(this); 0431 m_hexInput->setAlignment(Qt::AlignRight); 0432 0433 int digits = 2*m_color->colorSpace()->colorChannelCount(); 0434 QString pattern = QString("#?[a-fA-F0-9]{%1,%2}").arg(digits).arg(digits); 0435 m_hexInput->setValidator(new QRegExpValidator(QRegExp(pattern), this)); 0436 connect(m_hexInput, SIGNAL(editingFinished()), this, SLOT(setValue())); 0437 return m_hexInput; 0438 } 0439 0440 0441 KisHsvColorInput::KisHsvColorInput(QWidget *parent, KoColor *color) 0442 : QWidget(parent) 0443 , m_color(color) 0444 , m_hSlider(nullptr) 0445 , m_sSlider(nullptr) 0446 , m_xSlider(nullptr) 0447 , m_hInput(nullptr) 0448 , m_sInput(nullptr) 0449 , m_xInput(nullptr) 0450 , m_h(0) 0451 , m_s(0) 0452 , m_x(0) 0453 , m_mixMode(KisHsvColorSlider::MIX_MODE::HSV) 0454 { 0455 0456 QLabel *labels[3]; 0457 KisHsvColorSlider *sliders[3]; 0458 KisDoubleParseSpinBox *inputs[3]; 0459 const char *labelNames[3] = { "H:", "S:", "V:" }; 0460 qreal maxValues[3] = { 360, 100, 100 }; 0461 int labelWidth = 0; 0462 0463 QVBoxLayout *mainLayout = new QVBoxLayout(this); 0464 mainLayout->setContentsMargins(0,0,0,0); 0465 0466 for (int i = 0; i < 3; i++) { 0467 // Slider layout 0468 QHBoxLayout *sliderLayout = new QHBoxLayout(); 0469 sliderLayout->setContentsMargins(0,0,0,0); 0470 sliderLayout->setSpacing(1); 0471 0472 // Label 0473 QLabel *label = new QLabel(i18n(labelNames[i]), this); 0474 sliderLayout->addWidget(label); 0475 0476 // Slider itself 0477 KisHsvColorSlider *slider = new KisHsvColorSlider(Qt::Horizontal, this); 0478 slider->setMixMode(m_mixMode); 0479 slider->setMinimum(0); 0480 slider->setMaximum(maxValues[i]); 0481 slider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Fixed); 0482 sliderLayout->addWidget(slider); 0483 0484 // Input box 0485 KisDoubleParseSpinBox *input = new KisDoubleParseSpinBox(this); 0486 input->setMinimum(0); 0487 input->setMaximum(maxValues[i]); 0488 0489 input->setSizePolicy(QSizePolicy::Minimum, QSizePolicy::Preferred); 0490 input->setMinimumWidth(60); 0491 input->setMaximumWidth(60); 0492 0493 slider->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding); 0494 sliderLayout->addWidget(input); 0495 0496 mainLayout->addLayout(sliderLayout); 0497 0498 // Record max label width 0499 labelWidth = qMax(labelWidth, label->sizeHint().width()); 0500 0501 sliders[i] = slider; 0502 inputs[i] = input; 0503 labels[i] = label; 0504 } 0505 0506 // Align the labels 0507 for (int i = 0; i < 3; i++) { 0508 labels[i]->setMinimumWidth(labelWidth); 0509 } 0510 0511 // Connect slots 0512 connect(sliders[0], SIGNAL(valueChanged(int)), this, SLOT(hueSliderChanged(int))); 0513 connect(inputs[0], SIGNAL(valueChanged(double)), this, SLOT(setHue(double))); 0514 connect(sliders[1], SIGNAL(valueChanged(int)), this, SLOT(saturationSliderChanged(int))); 0515 connect(inputs[1], SIGNAL(valueChanged(double)), this, SLOT(setSaturation(double))); 0516 connect(sliders[2], SIGNAL(valueChanged(int)), this, SLOT(valueSliderChanged(int))); 0517 connect(inputs[2], SIGNAL(valueChanged(double)), this, SLOT(setValue(double))); 0518 0519 m_hSlider = sliders[0]; 0520 m_hSlider->setMixMode(KisHsvColorSlider::MIX_MODE::HSV); 0521 m_sSlider = sliders[1]; 0522 m_xSlider = sliders[2]; 0523 0524 m_hInput = inputs[0]; 0525 m_sInput = inputs[1]; 0526 m_xInput = inputs[2]; 0527 0528 // Set initial values 0529 QColor c = m_color->toQColor(); 0530 getHsxF(c, &m_h, &m_s, &m_x); 0531 0532 m_hInput->setValue(m_h); 0533 m_sInput->setValue(m_s); 0534 m_xInput->setValue(m_x); 0535 0536 // Update sliders 0537 QColor minC, maxC; 0538 minC.setHsvF(0, 1, 1); 0539 maxC.setHsvF(1, 1, 1); 0540 m_hSlider->setColors(minC, maxC); 0541 m_hSlider->setCircularHue(true); 0542 0543 recolorSliders(); 0544 } 0545 0546 void KisHsvColorInput::setMixMode(KisHsvColorSlider::MIX_MODE mixMode) { 0547 QColor c = m_color->toQColor(); 0548 m_mixMode = mixMode; 0549 getHsxF(c, &m_h, &m_s, &m_x); 0550 0551 m_sSlider->setMixMode(m_mixMode); 0552 m_xSlider->setMixMode(m_mixMode); 0553 0554 sendUpdate(); 0555 } 0556 0557 void KisHsvColorInput::sendUpdate() 0558 { 0559 { 0560 KisSignalsBlocker blocker( 0561 m_hSlider, m_sSlider, m_xSlider, 0562 m_hInput, m_sInput, m_xInput 0563 ); 0564 m_hSlider->setValue(m_h * 360); 0565 m_sSlider->setValue(m_s * 100); 0566 m_xSlider->setValue(m_x * 100); 0567 0568 m_hInput->setValue(m_h * 360); 0569 m_sInput->setValue(m_s * 100); 0570 m_xInput->setValue(m_x * 100); 0571 } 0572 0573 recolorSliders(); 0574 0575 QColor c; 0576 fillColor(c); 0577 0578 m_color->fromQColor(c); 0579 emit(updated()); 0580 } 0581 0582 void KisHsvColorInput::setHue(double x) 0583 { 0584 if (x < 0) { 0585 x = 0; 0586 } 0587 0588 if (x > 360) { 0589 x = 360; 0590 } 0591 0592 m_h = x / 360; 0593 sendUpdate(); 0594 } 0595 0596 void KisHsvColorInput::setSaturation(double x) 0597 { 0598 if (x < 0) { 0599 x = 0; 0600 } 0601 0602 if (x > 100) { 0603 x = 100; 0604 } 0605 0606 m_s = x / 100; 0607 sendUpdate(); 0608 } 0609 0610 void KisHsvColorInput::setValue(double x) 0611 { 0612 if (x < 0) { 0613 x = 0; 0614 } 0615 0616 if (x > 100) { 0617 x = 100; 0618 } 0619 0620 m_x = x / 100; 0621 sendUpdate(); 0622 } 0623 0624 void KisHsvColorInput::hueSliderChanged(int i) 0625 { 0626 m_hInput->setValue(i); 0627 } 0628 0629 void KisHsvColorInput::saturationSliderChanged(int i) 0630 { 0631 m_sInput->setValue(i); 0632 } 0633 0634 void KisHsvColorInput::valueSliderChanged(int i) 0635 { 0636 m_xInput->setValue(i); 0637 } 0638 0639 void KisHsvColorInput::recolorSliders() { 0640 // Update sliders 0641 QColor minC, maxC; 0642 0643 minC.setHsvF(m_h, 0, m_x); 0644 maxC.setHsvF(m_h, 1, m_x); 0645 m_sSlider->setColors(minC, maxC); 0646 0647 minC.setHsvF(m_h, m_s, 0); 0648 maxC.setHsvF(m_h, m_s, 1); 0649 m_xSlider->setColors(minC, maxC); 0650 } 0651 0652 void KisHsvColorInput::update() 0653 { 0654 KisSignalsBlocker blocker( 0655 m_hInput, m_sInput, m_xInput, 0656 m_hSlider, m_sSlider, m_xSlider 0657 ); 0658 0659 // Check if it is the same color we have 0660 QColor current; 0661 0662 fillColor(current); 0663 0664 QColor theirs = m_color->toQColor(); 0665 0666 // Truncate to integer for this check 0667 if (!(current.red() == theirs.red() && current.green() == theirs.green() && current.blue() == theirs.blue())) { 0668 // Apply the update 0669 qreal theirH; 0670 getHsxF(theirs, &theirH, &m_s, &m_x); 0671 0672 // Don't jump the Hue slider around to 0 if it is currently on 360 0673 const qreal EPSILON = 1e-6; 0674 if (!((1.0 - m_h) < EPSILON && (theirH - 0.0) < EPSILON)) { 0675 m_h = theirH; 0676 } 0677 0678 m_hInput->setValue(m_h * 360); 0679 m_sInput->setValue(m_s * 100); 0680 m_xInput->setValue(m_x * 100); 0681 0682 recolorSliders(); 0683 0684 // Update slider positions 0685 m_hSlider->setValue(m_h * 360); 0686 m_sSlider->setValue(m_s * 100); 0687 m_xSlider->setValue(m_x * 100); 0688 } 0689 } 0690 0691 void KisHsvColorInput::fillColor(QColor& c) { 0692 fillColor(c, m_h, m_s, m_x); 0693 } 0694 0695 void KisHsvColorInput::fillColor(QColor& c, const qreal& h, const qreal& s, const qreal& x) 0696 { 0697 switch (m_mixMode) { 0698 case KisHsvColorSlider::MIX_MODE::HSL: 0699 c.setHslF(h, s, x); 0700 break; 0701 0702 case KisHsvColorSlider::MIX_MODE::HSY: { 0703 qreal r, g, b; 0704 HSYToRGB(h, s, x, &r, &g, &b); 0705 0706 // Clamp 0707 r = qBound(0.0, r, 1.0); 0708 g = qBound(0.0, g, 1.0); 0709 b = qBound(0.0, b, 1.0); 0710 0711 c.setRgbF(r, g, b); 0712 break; 0713 } 0714 0715 case KisHsvColorSlider::MIX_MODE::HSI: { 0716 qreal r, g, b; 0717 HSIToRGB(h, s, x, &r, &g, &b); 0718 c.setRgbF(r, g, b); 0719 break; 0720 } 0721 0722 default: // fallthrough 0723 case KisHsvColorSlider::MIX_MODE::HSV: 0724 c.setHsvF(h, s, x); 0725 break; 0726 } 0727 } 0728 0729 void KisHsvColorInput::getHsxF(const QColor& color, qreal* h, qreal* s, qreal* x) 0730 { 0731 qreal tempH; 0732 switch (m_mixMode) { 0733 case KisHsvColorSlider::MIX_MODE::HSL: 0734 color.getHslF(&tempH, s, x); 0735 break; 0736 0737 case KisHsvColorSlider::MIX_MODE::HSY: { 0738 RGBToHSY(color.redF(), color.greenF(), color.blueF(), &tempH, s, x); 0739 break; 0740 } 0741 0742 case KisHsvColorSlider::MIX_MODE::HSI: { 0743 RGBToHSI(color.redF(), color.greenF(), color.blueF(), &tempH, s, x); 0744 break; 0745 } 0746 0747 default: // fallthrough 0748 case KisHsvColorSlider::MIX_MODE::HSV: 0749 color.getHsvF(&tempH, s, x); 0750 break; 0751 } 0752 0753 if (tempH >= 0.0 && tempH <= 1.0) { 0754 *h = tempH; 0755 } 0756 }