1 /*
2  *  Copyright (c) 2008 Cyrille Berger <cberger@cberger.net>
3  *  Copyright (c) 2015 Moritz Molch <kde@moritzmolch.de>
4  *
5  *  This library is free software; you can redistribute it and/or modify
6  *  it under the terms of the GNU Lesser General Public License as published by
7  *  the Free Software Foundation; version 2 of the License, or
8  *  (at your option) any later version.
9  *
10  *  This library is distributed in the hope that it will be useful,
11  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
12  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  *  GNU Lesser General Public License for more details.
14  *
15  *  You should have received a copy of the GNU Lesser General Public License
16  *  along with this program; if not, write to the Free Software
17  *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18  */
19 
20 #include "kis_specific_color_selector_widget.h"
21 #include <QLabel>
22 #include <QVBoxLayout>
23 #include <QCheckBox>
24 #include <QSpacerItem>
25 
26 #include <klocalizedstring.h>
27 #include <kconfiggroup.h>
28 #include <kconfig.h>
29 #include <ksharedconfig.h>
30 
31 #include <KoChannelInfo.h>
32 #include <KoColorSpace.h>
33 #include <KoColorSpaceRegistry.h>
34 #include <KoColorModelStandardIds.h>
35 
36 #include <kis_color_input.h>
37 #include <KoColorProfile.h>
38 #include <kis_debug.h>
39 #include <kis_color_space_selector.h>
40 #include <kis_signal_compressor.h>
41 #include <kis_display_color_converter.h>
42 #include <kis_popup_button.h>
43 #include <kis_icon_utils.h>
44 
45 #include "ui_wdgSpecificColorSelectorWidget.h"
46 
KisSpecificColorSelectorWidget(QWidget * parent)47 KisSpecificColorSelectorWidget::KisSpecificColorSelectorWidget(QWidget* parent)
48     : QWidget(parent)
49     , m_colorSpace(0)
50     , m_spacer(0)
51     , m_updateCompressor(new KisSignalCompressor(10, KisSignalCompressor::POSTPONE, this))
52     , m_customColorSpaceSelected(false)
53     , m_displayConverter(0)
54 {
55 
56     m_ui.reset(new Ui_wdgSpecificColorSelectorWidget());
57     m_ui->setupUi(this);
58 
59     m_updateAllowed = true;
60     connect(m_updateCompressor, SIGNAL(timeout()), SLOT(updateTimeout()));
61 
62     m_colorspaceSelector = new KisColorSpaceSelector(this);
63     connect(m_colorspaceSelector, SIGNAL(colorSpaceChanged(const KoColorSpace*)), this, SLOT(setCustomColorSpace(const KoColorSpace*)));
64 
65     m_ui->colorspacePopupButton->setPopupWidget(m_colorspaceSelector);
66 
67     connect(m_ui->chkUsePercentage, SIGNAL(toggled(bool)), this, SLOT(onChkUsePercentageChanged(bool)));
68 
69     KConfigGroup cfg =  KSharedConfig::openConfig()->group(QString());
70     m_ui->chkUsePercentage->setChecked(cfg.readEntry("SpecificColorSelector/UsePercentage", false));
71     m_ui->chkUsePercentage->setIcon(KisIconUtils::loadIcon("ratio"));
72 
73     m_colorspaceSelector->showColorBrowserButton(false);
74 
75     m_spacer = new QSpacerItem(0, 0, QSizePolicy::Expanding, QSizePolicy::Expanding);
76     m_ui->slidersLayout->addItem(m_spacer);
77 }
78 
~KisSpecificColorSelectorWidget()79 KisSpecificColorSelectorWidget::~KisSpecificColorSelectorWidget()
80 {
81     KConfigGroup cfg =  KSharedConfig::openConfig()->group(QString());
82     cfg.writeEntry("SpecificColorSelector/UsePercentage", m_ui->chkUsePercentage->isChecked());
83 }
84 
customColorSpaceUsed()85 bool KisSpecificColorSelectorWidget::customColorSpaceUsed()
86 {
87     return m_customColorSpaceSelected;
88 }
89 
resizeEvent(QResizeEvent * event)90 void KisSpecificColorSelectorWidget::resizeEvent(QResizeEvent *event)
91 {
92     QWidget::resizeEvent(event);
93 
94     if (m_colorSpace) {
95         QString elidedColorspaceName = m_ui->colorspacePopupButton->fontMetrics().elidedText(
96                     m_colorSpace->name(), Qt::ElideRight,
97                     m_ui->colorspacePopupButton->width()
98                     );
99         m_ui->colorspacePopupButton->setText(elidedColorspaceName);
100     }
101 }
102 
setDisplayConverter(KisDisplayColorConverter * displayConverter)103 void KisSpecificColorSelectorWidget::setDisplayConverter(KisDisplayColorConverter *displayConverter)
104 {
105     const bool needsForceUpdate = m_displayConverter != displayConverter;
106 
107     m_displayConverter = displayConverter;
108 
109     if (m_displayConverter) {
110         m_converterConnection.clear();
111         m_converterConnection.addConnection(m_displayConverter, SIGNAL(displayConfigurationChanged()), this, SLOT(rereadCurrentColorSpace()), Qt::UniqueConnection);
112     }
113 
114     rereadCurrentColorSpace(needsForceUpdate);
115 }
116 
rereadCurrentColorSpace(bool force)117 void KisSpecificColorSelectorWidget::rereadCurrentColorSpace(bool force)
118 {
119     if (m_displayConverter && !m_customColorSpaceSelected) {
120         m_colorSpace = m_displayConverter->paintingColorSpace();
121     }
122 
123     setColorSpace(m_colorSpace, force);
124     setColor(m_color);
125 }
126 
setColorSpace(const KoColorSpace * cs,bool force)127 void KisSpecificColorSelectorWidget::setColorSpace(const KoColorSpace* cs, bool force)
128 {
129     Q_ASSERT(cs);
130     dbgPlugins << cs->id() << " " << cs->profile()->name();
131 
132     if (*m_colorSpace == *cs && !force) {
133         Q_FOREACH (KisColorInput* input, m_inputs) {
134             input->update();
135         }
136 
137         return;
138     }
139 
140     if (cs->colorDepthId() == Integer8BitsColorDepthID || cs->colorDepthId() == Integer16BitsColorDepthID) {
141         m_ui->chkUsePercentage->setVisible(true);
142     } else {
143         m_ui->chkUsePercentage->setVisible(false);
144     }
145 
146     m_colorSpace = KoColorSpaceRegistry::instance()->colorSpace(cs->colorModelId().id(), cs->colorDepthId().id(), cs->profile());
147     Q_ASSERT(m_colorSpace);
148     Q_ASSERT(*m_colorSpace == *cs);
149 
150     QString elidedColorspaceName = m_ui->colorspacePopupButton->fontMetrics().elidedText(
151                 m_colorSpace->name(), Qt::ElideRight,
152                 m_ui->colorspacePopupButton->width()
153                 );
154     m_ui->colorspacePopupButton->setText(elidedColorspaceName);
155 
156     m_color = KoColor(m_color, m_colorSpace);
157     Q_FOREACH (KisColorInput* input, m_inputs) {
158         delete input;
159     }
160     m_inputs.clear();
161 
162     m_ui->slidersLayout->removeItem(m_spacer);
163 
164     QList<KoChannelInfo *> channels = KoChannelInfo::displayOrderSorted(m_colorSpace->channels());
165 
166     KoColorDisplayRendererInterface *displayRenderer =
167         m_displayConverter ?
168         m_displayConverter->displayRendererInterface() :
169         KisDisplayColorConverter::dumbConverterInstance()->displayRendererInterface();
170 
171     Q_FOREACH (KoChannelInfo* channel, channels) {
172         if (channel->channelType() == KoChannelInfo::COLOR) {
173             KisColorInput* input = 0;
174             switch (channel->channelValueType()) {
175             case KoChannelInfo::UINT8:
176             case KoChannelInfo::UINT16:
177             case KoChannelInfo::UINT32: {
178                 input = new KisIntegerColorInput(this, channel, &m_color, displayRenderer, m_ui->chkUsePercentage->isChecked());
179             }
180             break;
181             case KoChannelInfo::FLOAT16:
182             case KoChannelInfo::FLOAT32: {
183                 input = new KisFloatColorInput(this, channel, &m_color, displayRenderer);
184             }
185             break;
186             default:
187                 Q_ASSERT(false);
188                 input = 0;
189             }
190             if (input) {
191                 connect(input, SIGNAL(updated()), this,  SLOT(update()));
192                 connect(this,  SIGNAL(updated()), input, SLOT(update()));
193 
194                 m_inputs.append(input);
195                 m_ui->slidersLayout->addWidget(input);
196             }
197         }
198     }
199 
200     QList<QLabel*> labels;
201     int labelWidth = 0;
202 
203     Q_FOREACH (KisColorInput* input, m_inputs) {
204         Q_FOREACH (QLabel* label, input->findChildren<QLabel*>()) {
205             labels.append(label);
206             labelWidth = qMax(labelWidth, label->sizeHint().width());
207         }
208     }
209 
210     Q_FOREACH (QLabel *label, labels) {
211         label->setMinimumWidth(labelWidth);
212     }
213 
214     bool allChannels8Bit = true;
215     Q_FOREACH (KoChannelInfo* channel, channels) {
216         if (channel->channelType() == KoChannelInfo::COLOR && channel->channelValueType() != KoChannelInfo::UINT8) {
217             allChannels8Bit = false;
218         }
219     }
220     if (allChannels8Bit) {
221         KisColorInput* input = new KisHexColorInput(this, &m_color, displayRenderer);
222         m_inputs.append(input);
223         m_ui->slidersLayout->addWidget(input);
224         connect(input, SIGNAL(updated()), this,  SLOT(update()));
225         connect(this,  SIGNAL(updated()), input, SLOT(update()));
226     }
227     m_ui->slidersLayout->addItem(m_spacer);
228 
229     m_colorspaceSelector->blockSignals(true);
230     m_colorspaceSelector->setCurrentColorSpace(cs);
231     m_colorspaceSelector->blockSignals(false);
232 
233     m_updateAllowed = false;
234     emit(updated());
235     m_updateAllowed = true;
236 }
237 
update()238 void KisSpecificColorSelectorWidget::update()
239 {
240     if (m_updateAllowed) {
241         m_updateCompressor->start();
242     }
243 }
setColor(const KoColor & c)244 void KisSpecificColorSelectorWidget::setColor(const KoColor& c)
245 {
246     m_updateAllowed = false;
247     m_color.fromKoColor(c);
248     emit(updated());
249     m_updateAllowed = true;
250 }
251 
updateTimeout()252 void KisSpecificColorSelectorWidget::updateTimeout()
253 {
254     emit(colorChanged(m_color));
255 }
256 
setCustomColorSpace(const KoColorSpace * colorSpace)257 void KisSpecificColorSelectorWidget::setCustomColorSpace(const KoColorSpace *colorSpace)
258 {
259     m_customColorSpaceSelected = true;
260     setColorSpace(colorSpace);
261     setColor(m_color);
262 }
263 
onChkUsePercentageChanged(bool isChecked)264 void KisSpecificColorSelectorWidget::onChkUsePercentageChanged(bool isChecked)
265 {
266     for (auto input: m_inputs) {
267         input->setPercentageWise(isChecked);
268     }
269     emit(updated());
270 }
271