File indexing completed on 2024-05-12 16:02:01
0001 /* 0002 * SPDX-FileCopyrightText: 2016 Wolthera van Hovell tot Westerflier <griffinvalley@gmail.com> 0003 * SPDX-FileCopyrightText: 2020 L. E. Segovia <amy@amyspark.me> 0004 * 0005 * SPDX-License-Identifier: GPL-2.0-or-later 0006 */ 0007 #include "kis_spinbox_color_selector.h" 0008 #include <QFormLayout> 0009 #include <QLabel> 0010 #include "kis_double_parse_spin_box.h" 0011 #include "kis_int_parse_spin_box.h" 0012 #include "kis_signal_compressor.h" 0013 0014 #include <KoConfig.h> 0015 #ifdef HAVE_OPENEXR 0016 #include <half.h> 0017 #endif 0018 #include <KoChannelInfo.h> 0019 #include <KoColorModelStandardIds.h> 0020 #include <KoColorSpaceTraits.h> 0021 #include <KoColorSpaceMaths.h> 0022 #include <KoColorSpaceRegistry.h> 0023 0024 struct KisSpinboxColorSelector::Private 0025 { 0026 QList <QLabel*> labels; 0027 QList <KisIntParseSpinBox*> spinBoxList; 0028 QList <KisDoubleParseSpinBox*> doubleSpinBoxList; 0029 KoColor color; 0030 const KoColorSpace *cs {0}; 0031 bool chooseAlpha {false}; 0032 QFormLayout *layout {0}; 0033 }; 0034 0035 KisSpinboxColorSelector::KisSpinboxColorSelector(QWidget *parent) 0036 : QWidget(parent) 0037 , m_d(new Private) 0038 { 0039 this->setSizePolicy(QSizePolicy::Expanding,QSizePolicy::Expanding); 0040 m_d->layout = new QFormLayout(this); 0041 } 0042 0043 KisSpinboxColorSelector::~KisSpinboxColorSelector() 0044 { 0045 0046 } 0047 0048 void KisSpinboxColorSelector::slotSetColor(KoColor color) 0049 { 0050 m_d->color = color; 0051 slotSetColorSpace(m_d->color.colorSpace()); 0052 updateSpinboxesWithNewValues(); 0053 } 0054 0055 void KisSpinboxColorSelector::slotSetColorSpace(const KoColorSpace *cs) 0056 { 0057 if (cs == m_d->cs) { 0058 return; 0059 } 0060 0061 m_d->cs = cs; 0062 //remake spinboxes 0063 delete m_d->layout; 0064 m_d->layout = new QFormLayout(this); 0065 0066 Q_FOREACH(QObject *o, m_d->labels) { 0067 o->deleteLater(); 0068 } 0069 Q_FOREACH(QObject *o, m_d->spinBoxList) { 0070 o->deleteLater(); 0071 } 0072 Q_FOREACH(QObject *o, m_d->doubleSpinBoxList) { 0073 o->deleteLater(); 0074 } 0075 0076 m_d->labels.clear(); 0077 m_d->spinBoxList.clear(); 0078 m_d->doubleSpinBoxList.clear(); 0079 0080 QList<KoChannelInfo *> channels = KoChannelInfo::displayOrderSorted(m_d->cs->channels()); 0081 Q_FOREACH (KoChannelInfo* channel, channels) { 0082 QString inputLabel = channel->name() + ":"; 0083 QLabel *inlb = new QLabel(this); 0084 m_d->labels << inlb; 0085 inlb->setText(inputLabel); 0086 switch (channel->channelValueType()) { 0087 case KoChannelInfo::UINT8: { 0088 KisIntParseSpinBox *input = new KisIntParseSpinBox(this); 0089 input->setMinimum(0); 0090 input->setMaximum(0xFF); 0091 m_d->spinBoxList.append(input); 0092 connect(input, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateFromSpinBoxes())); 0093 if (channel->channelType() == KoChannelInfo::ALPHA && m_d->chooseAlpha == false) { 0094 inlb->setVisible(false); 0095 input->setVisible(false); 0096 input->blockSignals(true); 0097 } 0098 else { 0099 m_d->layout->addRow(inlb, input); 0100 } 0101 } 0102 break; 0103 case KoChannelInfo::UINT16: { 0104 KisIntParseSpinBox *input = new KisIntParseSpinBox(this); 0105 input->setMinimum(0); 0106 input->setMaximum(0xFFFF); 0107 m_d->spinBoxList.append(input); 0108 connect(input, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateFromSpinBoxes())); 0109 if (channel->channelType() == KoChannelInfo::ALPHA && m_d->chooseAlpha == false) { 0110 inlb->setVisible(false); 0111 input->setVisible(false); 0112 input->blockSignals(true); 0113 } 0114 else { 0115 m_d->layout->addRow(inlb,input); 0116 } 0117 } 0118 break; 0119 case KoChannelInfo::UINT32: { 0120 KisIntParseSpinBox *input = new KisIntParseSpinBox(this); 0121 input->setMinimum(0); 0122 input->setMaximum(0xFFFFFFFF); 0123 m_d->spinBoxList.append(input); 0124 connect(input, SIGNAL(valueChanged(int)), this, SLOT(slotUpdateFromSpinBoxes())); 0125 if (channel->channelType() == KoChannelInfo::ALPHA && m_d->chooseAlpha == false) { 0126 inlb->setVisible(false); 0127 input->setVisible(false); 0128 input->blockSignals(true); 0129 } 0130 else { 0131 m_d->layout->addRow(inlb,input); 0132 } 0133 } 0134 break; 0135 #ifdef HAVE_OPENEXR 0136 case KoChannelInfo::FLOAT16: { 0137 half m_uiMin, m_uiMax; 0138 if (cs->colorModelId() == LABAColorModelID || cs->colorModelId() == CMYKAColorModelID) { 0139 m_uiMin = channel->getUIMin(); 0140 m_uiMax = channel->getUIMax(); 0141 } else { 0142 m_uiMin = 0; 0143 m_uiMax = KoColorSpaceMathsTraits<half>::max; 0144 } 0145 0146 KisDoubleParseSpinBox *input = new KisDoubleParseSpinBox(this); 0147 input->setMinimum(m_uiMin); 0148 input->setMaximum(m_uiMax); 0149 input->setSingleStep(0.1); 0150 m_d->doubleSpinBoxList.append(input); 0151 connect(input, SIGNAL(valueChanged(double)), this, SLOT(slotUpdateFromSpinBoxes())); 0152 if (channel->channelType() == KoChannelInfo::ALPHA && m_d->chooseAlpha == false) { 0153 inlb->setVisible(false); 0154 input->setVisible(false); 0155 input->blockSignals(true); 0156 } 0157 else { 0158 m_d->layout->addRow(inlb,input); 0159 } 0160 } 0161 break; 0162 #endif 0163 case KoChannelInfo::FLOAT32: { 0164 float m_uiMin, m_uiMax; 0165 if (cs->colorModelId() == LABAColorModelID || cs->colorModelId() == CMYKAColorModelID) { 0166 m_uiMin = channel->getUIMin(); 0167 m_uiMax = channel->getUIMax(); 0168 } else { 0169 m_uiMin = 0; 0170 m_uiMax = KoColorSpaceMathsTraits<float>::max; 0171 } 0172 0173 KisDoubleParseSpinBox *input = new KisDoubleParseSpinBox(this); 0174 input->setMinimum(m_uiMin); 0175 input->setMaximum(m_uiMax); 0176 input->setSingleStep(0.1); 0177 m_d->doubleSpinBoxList.append(input); 0178 connect(input, SIGNAL(valueChanged(double)), this, SLOT(slotUpdateFromSpinBoxes())); 0179 if (channel->channelType() == KoChannelInfo::ALPHA && m_d->chooseAlpha == false) { 0180 inlb->setVisible(false); 0181 input->setVisible(false); 0182 input->blockSignals(true); 0183 } 0184 else { 0185 m_d->layout->addRow(inlb,input); 0186 } 0187 } 0188 break; 0189 default: 0190 Q_ASSERT(false); 0191 } 0192 0193 } 0194 } 0195 0196 void KisSpinboxColorSelector::createColorFromSpinboxValues() 0197 { 0198 KoColor newColor(m_d->cs); 0199 int channelcount = m_d->cs->channelCount(); 0200 QVector <float> channelValues(channelcount); 0201 channelValues.fill(1.0); 0202 QList<KoChannelInfo *> channels = KoChannelInfo::displayOrderSorted(m_d->cs->channels()); 0203 0204 for (int i = 0; i < (int)qAbs(m_d->cs->colorChannelCount()); i++) { 0205 int channelposition = KoChannelInfo::displayPositionToChannelIndex(i, m_d->cs->channels()); 0206 0207 if (channels.at(i)->channelValueType()==KoChannelInfo::UINT8 && m_d->spinBoxList.at(i)){ 0208 0209 int value = m_d->spinBoxList.at(i)->value(); 0210 channelValues[channelposition] = KoColorSpaceMaths<quint8,float>::scaleToA(value); 0211 0212 } else if (channels.at(i)->channelValueType()==KoChannelInfo::UINT16 && m_d->spinBoxList.at(i)){ 0213 0214 channelValues[channelposition] = KoColorSpaceMaths<quint16,float>::scaleToA(m_d->spinBoxList.at(i)->value()); 0215 0216 } else if ((channels.at(i)->channelValueType()==KoChannelInfo::FLOAT16 || 0217 channels.at(i)->channelValueType()==KoChannelInfo::FLOAT32 || 0218 channels.at(i)->channelValueType()==KoChannelInfo::FLOAT64) && m_d->doubleSpinBoxList.at(i)) { 0219 0220 channelValues[channelposition] = m_d->doubleSpinBoxList.at(i)->value(); 0221 0222 } 0223 } 0224 0225 m_d->cs->fromNormalisedChannelsValue(newColor.data(), channelValues); 0226 newColor.setOpacity(m_d->color.opacityU8()); 0227 0228 m_d->color = newColor; 0229 } 0230 0231 void KisSpinboxColorSelector::slotUpdateFromSpinBoxes() 0232 { 0233 createColorFromSpinboxValues(); 0234 emit sigNewColor(m_d->color); 0235 } 0236 0237 void KisSpinboxColorSelector::updateSpinboxesWithNewValues() 0238 { 0239 int channelcount = m_d->cs->channelCount(); 0240 QVector <float> channelValues(channelcount); 0241 channelValues.fill(1.0); 0242 m_d->cs->normalisedChannelsValue(m_d->color.data(), channelValues); 0243 QList<KoChannelInfo *> channels = KoChannelInfo::displayOrderSorted(m_d->cs->channels()); 0244 0245 int i; 0246 /*while (QLayoutItem *item = this->layout()->takeAt(0)) 0247 { 0248 item->widget()->blockSignals(true); 0249 }*/ 0250 for (i=0; i<m_d->spinBoxList.size(); i++) { 0251 m_d->spinBoxList.at(i)->blockSignals(true); 0252 } 0253 for (i=0; i<m_d->doubleSpinBoxList.size(); i++) { 0254 m_d->doubleSpinBoxList.at(i)->blockSignals(true); 0255 } 0256 0257 for (i = 0; i < (int)qAbs(m_d->cs->colorChannelCount()); i++) { 0258 int channelposition = KoChannelInfo::displayPositionToChannelIndex(i, m_d->cs->channels()); 0259 if (channels.at(i)->channelValueType() == KoChannelInfo::UINT8 && m_d->spinBoxList.at(i)) { 0260 int value = KoColorSpaceMaths<float, quint8>::scaleToA(channelValues[channelposition]); 0261 m_d->spinBoxList.at(i)->setValue(value); 0262 } else if (channels.at(i)->channelValueType() == KoChannelInfo::UINT16 && m_d->spinBoxList.at(i)) { 0263 m_d->spinBoxList.at(i)->setValue(KoColorSpaceMaths<float, quint16>::scaleToA(channelValues[channelposition])); 0264 } else if ((channels.at(i)->channelValueType()==KoChannelInfo::FLOAT16 || 0265 channels.at(i)->channelValueType()==KoChannelInfo::FLOAT32 || 0266 channels.at(i)->channelValueType()==KoChannelInfo::FLOAT64) && m_d->doubleSpinBoxList.at(i)) { 0267 float value = channels.at(i)->getUIMin() + channelValues[channelposition] * channels.at(i)->getUIUnitValue(); 0268 m_d->doubleSpinBoxList.at(i)->setValue(value); 0269 } 0270 } 0271 0272 for (i=0; i<m_d->spinBoxList.size(); i++) { 0273 m_d->spinBoxList.at(i)->blockSignals(false); 0274 } 0275 for (i=0; i<m_d->doubleSpinBoxList.size(); i++) { 0276 m_d->doubleSpinBoxList.at(i)->blockSignals(false); 0277 } 0278 /*while (QLayoutItem *item = this->layout()->takeAt(0)) 0279 { 0280 item->widget()->blockSignals(false); 0281 }*/ 0282 } 0283 0284