Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tool_colorsampler.cc
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 1999 Matthias Elter <me@kde.org>
3 * SPDX-FileCopyrightText: 2002 Patrick Julien <freak@codepimps.org>
4 * SPDX-FileCopyrightText: 2010 Lukáš Tvrdý <lukast.dev@gmail.com>
5 * SPDX-FileCopyrightText: 2018 Emmet & Eoin O'Neill <emmetoneill.pdx@gmail.com>
6 *
7 * SPDX-License-Identifier: GPL-2.0-or-later
8 */
9
11
12#include <kis_cursor.h>
13#include <kis_canvas2.h>
14#include <KoCanvasBase.h>
19#include <KisResourceTypes.h>
20#include <KisViewManager.h>
22#include "kis_tool_utils.h"
23
24
25namespace
26{
27// GUI ComboBox index constants
28const int SAMPLE_MERGED = 0;
29}
30
32 : KisTool(canvas, KisCursor::samplerCursor()),
33 m_config(new KisToolUtils::ColorSamplerConfig),
34 m_helper(dynamic_cast<KisCanvas2*>(canvas))
35{
36 setObjectName("tool_colorsampler");
37 connect(&m_helper, SIGNAL(sigRequestCursor(QCursor)), this, SLOT(slotColorPickerRequestedCursor(QCursor)));
38 connect(&m_helper, SIGNAL(sigRequestCursorReset()), this, SLOT(slotColorPickerRequestedCursorReset()));
39 connect(&m_helper, SIGNAL(sigRequestUpdateOutline()), this, SLOT(slotColorPickerRequestedOutlineUpdate()));
40 connect(&m_helper, SIGNAL(sigRawColorSelected(KoColor)), this, SLOT(slotColorPickerSelectedColor(KoColor)));
41 connect(&m_helper, SIGNAL(sigFinalColorSelected(KoColor)), this, SLOT(slotColorPickerSelectionFinished(KoColor)));
42}
43
50
55
61
66
76
78{
79 Q_UNUSED(color);
80
81 if (m_config->addColorToCurrentPalette) {
82 KisSwatch swatch;
83 swatch.setColor(color);
84 // We don't ask for a name, too intrusive here
85
86 QModelIndex idx = m_tagFilterProxyModel->index(m_optionsWidget->cmbPalette->currentIndex(), 0);
87 KoColorSetSP palette = qSharedPointerDynamicCast<KoColorSet>(m_tagFilterProxyModel->resourceForIndex(idx));
88
89 if (palette) {
90 KisSwatchGroup::SwatchInfo info =
91 palette->getClosestSwatchInfo(color);
92
93 if (info.swatch.color() != color) {
94 palette->addSwatch(swatch);
95 }
96 }
97 }
98}
99
100void KisToolColorSampler::paint(QPainter &gc, const KoViewConverter &converter)
101{
102 m_helper.paint(gc, converter);
103}
104
105void KisToolColorSampler::activate(const QSet<KoShape*> &shapes)
106{
107
108 m_isActivated = true;
109 m_config->load();
110
112
113 KisTool::activate(shapes);
114}
115
117{
118 m_config->save();
119
120 m_isActivated = false;
122}
123
125{
127
128 bool useOtherColor = canvas()->resourceManager()->boolResource(KoCanvasResource::UsingOtherColor);
129 // if useOtherColor is true, apply to the other color than that configured in the tool options
130 m_helper.activate(!m_config->sampleMerged, m_config->toForegroundColor != useOtherColor);
131 m_helper.startAction(event->point, m_config->radius, m_config->blend);
132 requestUpdateOutline(event->point, event);
133
135}
136
140
148
159{
164 bool useOtherColor = canvas()->resourceManager()->boolResource(KoCanvasResource::UsingOtherColor);
165 // if useOtherColor is true, apply to the other color than that configured in the tool options
166 m_helper.updateCursor(!m_config->sampleMerged, m_config->toForegroundColor != useOtherColor);
167}
168
176
177void KisToolColorSampler::requestUpdateOutline(const QPointF &outlineDocPoint, const KoPointerEvent *event)
178{
179 Q_UNUSED(event);
180
181 KisConfig cfg(true);
182
183 QRectF colorPreviewDocUpdateRect;
184
185 qreal zoomX;
186 qreal zoomY;
187 canvas()->viewConverter()->zoom(&zoomX, &zoomY);
188 qreal xoffset = 2.0/zoomX;
189 qreal yoffset = 2.0/zoomY;
190
191 m_outlineDocPoint = outlineDocPoint;
192
193 colorPreviewDocUpdateRect = m_helper.colorPreviewDocRect(m_outlineDocPoint);
194
195 if (!colorPreviewDocUpdateRect.isEmpty()) {
196 colorPreviewDocUpdateRect = colorPreviewDocUpdateRect.adjusted(-xoffset,-yoffset,xoffset,yoffset);
197 }
198
199 if (!m_oldColorPreviewUpdateRect.isEmpty()){
201 }
202
203 if (!colorPreviewDocUpdateRect.isEmpty()){
204 canvas()->updateCanvas(colorPreviewDocUpdateRect);
205 }
206
207 m_oldColorPreviewUpdateRect = colorPreviewDocUpdateRect;
208}
209
210
212 QString name;
213 QString valueText;
214};
215
217{
218 if (color.data() && m_optionsWidget) {
219
220 const QList<KoChannelInfo *> channels = color.colorSpace()->channels();
221 m_optionsWidget->listViewChannels->clear();
222
223 QVector<SampledChannel> sampledChannels;
224 for (int i = 0; i < channels.count(); ++i) {
225 sampledChannels.append(SampledChannel());
226 }
227
228 for (int i = 0; i < channels.count(); ++i) {
229
231 pc.name = channels[i]->name();
232
233 if (m_config->normaliseValues) {
234 pc.valueText = color.colorSpace()->normalisedChannelValueText(color.data(), i);
235 } else {
236 pc.valueText = color.colorSpace()->channelValueText(color.data(), i);
237 }
238
239 sampledChannels[channels[i]->displayPosition()] = pc;
240
241 }
242
243 Q_FOREACH (const SampledChannel &pc, sampledChannels) {
244 QTreeWidgetItem *item = new QTreeWidgetItem(m_optionsWidget->listViewChannels);
245 item->setText(0, pc.name);
246 item->setText(1, pc.valueText);
247 }
248
249
250 if (qEnvironmentVariableIsSet("KRITA_DEBUG_DISPLAY_COLOR")) {
251 KisCanvas2 *kritaCanvas = dynamic_cast<KisCanvas2*>(canvas());
252 KIS_ASSERT(kritaCanvas);
255
256 QVector<float> values(4);
257 newColor.colorSpace()->normalisedChannelsValue(newColor.data(), values);
258
259 for (int i = 0; i < values.size(); i++) {
260 QTreeWidgetItem *item = new QTreeWidgetItem(m_optionsWidget->listViewChannels);
261 item->setText(0, QString("DisplayCh%1").arg(i));
262 item->setText(1, QString::number(values[i]));
263 }
264 }
265 }
266}
267
269{
271 m_optionsWidget->setObjectName(toolId() + " option widget");
272 m_optionsWidget->listViewChannels->setSortingEnabled(false);
273
274 // See https://bugs.kde.org/show_bug.cgi?id=316896
275 QWidget *specialSpacer = new QWidget(m_optionsWidget);
276 specialSpacer->setObjectName("SpecialSpacer");
277 specialSpacer->setFixedSize(0, 0);
278 m_optionsWidget->layout()->addWidget(specialSpacer);
279
280 // Initialize blend KisSliderSpinBox
281 m_optionsWidget->blend->setRange(0,100);
283 i18nc("{n} is the number value, % is the percent sign", "{n}%"));
284
286
287 connect(m_optionsWidget->cbUpdateCurrentColor, SIGNAL(toggled(bool)), SLOT(slotSetUpdateColor(bool)));
288 connect(m_optionsWidget->cbNormaliseValues, SIGNAL(toggled(bool)), SLOT(slotSetNormaliseValues(bool)));
289 connect(m_optionsWidget->cbPalette, SIGNAL(toggled(bool)),
290 SLOT(slotSetAddPalette(bool)));
291 connect(m_optionsWidget->radius, SIGNAL(valueChanged(int)),
292 SLOT(slotChangeRadius(int)));
293 connect(m_optionsWidget->blend, SIGNAL(valueChanged(int)),
294 SLOT(slotChangeBlend(int)));
295 connect(m_optionsWidget->cmbSources, SIGNAL(currentIndexChanged(int)),
296 SLOT(slotSetColorSource(int)));
297
299 m_optionsWidget->cmbPalette->setModel(m_tagFilterProxyModel);
300 m_optionsWidget->cmbPalette->setModelColumn(KisAbstractResourceModel::Name);
301 m_tagFilterProxyModel->sort(Qt::DisplayRole);
302
303
304 KConfigGroup config = KSharedConfig::openConfig()->group(toolId());
305 QString paletteName = config.readEntry("ColorSamplerPalette", "");
306 if (!paletteName.isEmpty()) {
307 for (int i = 0; i < m_tagFilterProxyModel->rowCount(); i++) {
308 QModelIndex idx = m_tagFilterProxyModel->index(i, 0);
309 QString name = m_tagFilterProxyModel->data(idx, Qt::UserRole + KisAbstractResourceModel::Name).toString();
310 if (name == paletteName) {
311 m_optionsWidget->cmbPalette->setCurrentIndex(i);
312 break;
313 }
314 }
315 }
316
317 connect(m_optionsWidget->cmbPalette, SIGNAL(currentIndexChanged(int)), SLOT(slotChangePalette(int)));
318
319 return m_optionsWidget;
320}
321
323{
324 if (!m_optionsWidget) return;
325
326 m_optionsWidget->cbNormaliseValues->setChecked(m_config->normaliseValues);
327 m_optionsWidget->cbUpdateCurrentColor->setChecked(m_config->updateColor);
328 m_optionsWidget->cmbSources->setCurrentIndex(SAMPLE_MERGED + !m_config->sampleMerged);
329 m_optionsWidget->cbPalette->setChecked(m_config->addColorToCurrentPalette);
330 m_optionsWidget->radius->setValue(m_config->radius);
331 m_optionsWidget->blend->setValue(m_config->blend);
332}
333
335{
336 m_config->updateColor = state;
337}
338
340{
341 m_config->normaliseValues = state;
343}
344
346{
347 m_config->addColorToCurrentPalette = state;
348}
349
354
359
361{
362 m_config->sampleMerged = value == SAMPLE_MERGED;
363}
364
366{
367 QString paletteName = m_optionsWidget->cmbPalette->currentData(Qt::UserRole + KisAbstractResourceModel::Name).toString();
368 KConfigGroup config = KSharedConfig::openConfig()->group(toolId());
369 config.writeEntry("ColorSamplerPalette", paletteName);
370}
float value(const T *src, size_t ch)
const KoID Float32BitsColorDepthID("F32", ki18n("32-bit float/channel"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
void activate(bool sampleCurrentLayer, bool pickFgColor)
void paint(QPainter &gc, const KoViewConverter &converter)
void updateCursor(bool sampleCurrentLayer, bool pickFgColor)
void continueAction(const QPointF &docPoint)
void startAction(const QPointF &docPoint, int radius, int blend)
QRectF colorPreviewDocRect(const QPointF &docPoint)
KisDisplayColorConverter displayColorConverter
void updateCanvas(const QRectF &rc) override
const KoViewConverter * viewConverter() const override
KoColor applyDisplayFiltering(const KoColor &srcColor, const KoID &bitDepthId) const
void setColor(const KoColor &color)
Definition KisSwatch.cpp:32
The KisTagFilterResourceProxyModel class filters the resources by tag or resource name.
KoResourceSP resourceForIndex(QModelIndex index=QModelIndex()) const override
resourceForIndex returns a properly versioned and id'ed resource object
void slotSetColorSource(int value)
KisTagFilterResourceProxyModel * m_tagFilterProxyModel
void slotColorPickerRequestedCursor(const QCursor &cursor)
void paint(QPainter &gc, const KoViewConverter &converter) override
QWidget * createOptionWidget() override
void displaySampledColor(const KoColor &color)
void slotColorPickerSelectedColor(const KoColor &color)
void endPrimaryAction(KoPointerEvent *event) override
QScopedPointer< KisToolUtils::ColorSamplerConfig > m_config
void beginPrimaryAction(KoPointerEvent *event) override
void continuePrimaryAction(KoPointerEvent *event) override
void activate(const QSet< KoShape * > &) override
KisToolColorSampler(KoCanvasBase *canvas)
ColorSamplerOptionsWidget * m_optionsWidget
KisAsyncColorSamplerHelper m_helper
void deactivatePrimaryAction() override
void requestUpdateOutline(const QPointF &outlineDocPoint, const KoPointerEvent *event)
void activatePrimaryAction() override
void slotColorPickerSelectionFinished(const KoColor &color)
void mouseMoveEvent(KoPointerEvent *event) override
QPointer< KoCanvasResourceProvider > resourceManager
virtual QString channelValueText(const quint8 *pixel, quint32 channelIndex) const =0
QList< KoChannelInfo * > channels
virtual KoID colorModelId() const =0
virtual void normalisedChannelsValue(const quint8 *pixel, QVector< float > &channels) const =0
virtual QString normalisedChannelValueText(const quint8 *pixel, quint32 channelIndex) const =0
quint8 * data()
Definition KoColor.h:144
const KoColorSpace * colorSpace() const
return the current colorSpace
Definition KoColor.h:82
QPointF point
The point in document coordinates.
Q_INVOKABLE QString toolId() const
void useCursor(const QCursor &cursor)
virtual void zoom(qreal *zoomX, qreal *zoomY) const
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
#define CHECK_MODE_SANITY_OR_RETURN(_mode)
Definition kis_tool.h:27
void setText(QSpinBox *spinBox, const QStringView textTemplate)
const QString Palettes
rgba palette[MAX_PALETTE]
Definition palette.c:35
void mouseMoveEvent(KoPointerEvent *event) override
Definition kis_tool.cc:520
void activate(const QSet< KoShape * > &shapes) override
Definition kis_tool.cc:93
void deactivate() override
Definition kis_tool.cc:131
@ PAINT_MODE
Definition kis_tool.h:300
QCursor cursor
Definition kis_tool.cc:64
virtual void setMode(ToolMode mode)
Definition kis_tool.cc:403
KisCanvas2 * canvas