Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_tool_lazy_brush_options_widget.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2016 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include "ui_kis_tool_lazy_brush_options_widget.h"
10
11#include <QWheelEvent>
13#include "KisPaletteModel.h"
15
16#include "kis_config.h"
21#include "kis_image.h"
22#include "kis_signals_blocker.h"
25
47
48struct PaletteEventFilter : public QObject
49{
50 bool eventFilter(QObject *watched, QEvent *event) override
51 {
52 if (event->type() == QEvent::Wheel) {
53 QWheelEvent *wevent = static_cast<QWheelEvent*>(event);
54
55 if (wevent->modifiers() == Qt::ControlModifier) {
56 if (watched == m_parentView->viewport()) {
57 const int columnCountDelta = -wevent->angleDelta().y() / QWheelEvent::DefaultDeltasPerStep;
58 const int newColumnCount = qMax(1, m_optionsWidget->m_d->preferredColumnCount + columnCountDelta);
59
60 m_optionsWidget->m_d->preferredColumnCount = newColumnCount;
62 }
63
64 return true;
65 }
66
67 }
68
69 return QObject::eventFilter(watched, event);
70 }
71
73 : QObject(optionsWidget),
74 m_parentView(parentView),
75 m_optionsWidget(optionsWidget)
76
77 {}
78
81};
82
84 : QWidget(parent),
85 m_d(new Private)
86{
87 m_d->ui = new Ui_KisToolLazyBrushOptionsWidget();
88 m_d->ui->setupUi(this);
89
90 m_d->colorModel = new KisPaletteModel(this);
91 m_d->ui->colorView->setPaletteModel(m_d->colorModel);
92 m_d->ui->colorView->setAllowModification(false); //people probably shouldn't be able to edit the colorentries themselves.
93 m_d->ui->colorView->setCrossedKeyword("transparent");
94
95 PaletteEventFilter *filter = new PaletteEventFilter(m_d->ui->colorView, this);
96 m_d->ui->colorView->viewport()->installEventFilter(filter);
97
98 connect(m_d->ui->chkUseEdgeDetection, SIGNAL(toggled(bool)), SLOT(slotUseEdgeDetectionChanged(bool)));
99 connect(m_d->ui->intEdgeDetectionSize, SIGNAL(valueChanged(int)), SLOT(slotEdgeDetectionSizeChanged(int)));
100 connect(m_d->ui->intRadius, SIGNAL(valueChanged(int)), SLOT(slotRadiusChanged(int)));
101 connect(m_d->ui->intCleanUp, SIGNAL(valueChanged(int)), SLOT(slotCleanUpChanged(int)));
102 connect(m_d->ui->chkLimitToDevice, SIGNAL(toggled(bool)), SLOT(slotLimitToDeviceChanged(bool)));
103
104 m_d->ui->intEdgeDetectionSize->setRange(0, 100);
105 m_d->ui->intEdgeDetectionSize->setExponentRatio(2.0);
106 m_d->ui->intEdgeDetectionSize->setSuffix(i18n(" px"));
107 m_d->ui->intEdgeDetectionSize->setPrefix(i18n("Edge detection: "));
108 m_d->ui->intEdgeDetectionSize->setToolTip(
109 i18nc("@info:tooltip",
110 "Activate for images with vast solid areas. "
111 "Set the value to the width of the thinnest "
112 "lines on the image"));
113
114 m_d->ui->intRadius->setRange(0, 1000);
115 m_d->ui->intRadius->setExponentRatio(3.0);
116 m_d->ui->intRadius->setSuffix(i18n(" px"));
117 m_d->ui->intRadius->setPrefix(i18n("Gap close hint: "));
118 m_d->ui->intRadius->setToolTip(
119 i18nc("@info:tooltip",
120 "The mask will try to close non-closed contours "
121 "if the gap is smaller than \"Gap close hint\" value"));
122
123 m_d->ui->intCleanUp->setRange(0, 100);
124 KisSpinBoxI18nHelper::setText(m_d->ui->intCleanUp,
125 i18nc("{n} is the number value, % is the percent sign", "Clean up: {n}%"));
126 m_d->ui->intCleanUp->setToolTip(
127 i18nc("@info:tooltip",
128 "The mask will try to remove parts of the key strokes "
129 "that are placed outside the closed contours. 0% - no effect, 100% - max effect"));
130
131
132 connect(m_d->ui->colorView, SIGNAL(sigIndexSelected(QModelIndex)), this, SLOT(entrySelected(QModelIndex)));
133 connect(m_d->ui->btnTransparent, SIGNAL(toggled(bool)), this, SLOT(slotMakeTransparent(bool)));
134 connect(m_d->ui->btnRemove, SIGNAL(clicked()), this, SLOT(slotRemove()));
135
136 connect(m_d->ui->chkAutoUpdates, SIGNAL(toggled(bool)), m_d->ui->btnUpdate, SLOT(setDisabled(bool)));
137
138 connect(m_d->ui->btnUpdate, SIGNAL(clicked()), this, SLOT(slotUpdate()));
139 connect(m_d->ui->chkAutoUpdates, SIGNAL(toggled(bool)), this, SLOT(slotSetAutoUpdates(bool)));
140 connect(m_d->ui->chkShowKeyStrokes, SIGNAL(toggled(bool)), this, SLOT(slotSetShowKeyStrokes(bool)));
141 connect(m_d->ui->chkShowOutput, SIGNAL(toggled(bool)), this, SLOT(slotSetShowOutput(bool)));
142
143 connect(&m_d->baseNodeChangedCompressor, SIGNAL(timeout()), this, SLOT(slotUpdateNodeProperties()));
144
145 m_d->provider = provider;
146
147 m_d->colorModel->setColorSet(m_d->colorSet);
148
150
151 m_d->colorModel->addSwatch(KisSwatch(KoColor(Qt::red, cs), "color1"));
152 m_d->colorModel->addSwatch(KisSwatch(KoColor(Qt::green, cs), "color2"));
153 m_d->colorModel->addSwatch(KisSwatch(KoColor(Qt::blue, cs), "color3"));
154}
155
157{
158 delete m_d->ui;
159 m_d->ui = nullptr;
160}
161
163{
164 QWidget::showEvent(event);
165
166 m_d->providerSignals.addConnection(
167 m_d->provider, SIGNAL(sigNodeChanged(KisNodeSP)),
168 this, SLOT(slotCurrentNodeChanged(KisNodeSP)));
169
170 m_d->providerSignals.addConnection(
171 m_d->provider, SIGNAL(sigFGColorChanged(KoColor)),
173
174 slotCurrentNodeChanged(m_d->provider->currentNode());
175 slotCurrentFgColorChanged(m_d->provider->fgColor());
176}
177
179{
180 QWidget::hideEvent(event);
181
182 m_d->providerSignals.clear();
183}
184
186{
187 if (!index.isValid()) return;
188 if (!qvariant_cast<bool>(index.data(KisPaletteModel::CheckSlotRole))) return;
189
190 KisSwatch entry = m_d->colorModel->getSwatch(index);
191 m_d->provider->setFGColor(entry.color());
192
193 int idxInList = m_d->activeMask->keyStrokesColors().colors.indexOf(entry.color());
194
195 if (idxInList != -1) {
196 const bool transparentChecked = idxInList == m_d->transparentColorIndex;
197 KisSignalsBlocker b(m_d->ui->btnTransparent);
198 m_d->ui->btnTransparent->setChecked(transparentChecked);
199 }
200}
201
203{
204 bool found = false;
205
206 QModelIndex candidateIdx = m_d->colorModel->indexForClosest(color);
207 if (m_d->colorModel->getSwatch(candidateIdx).color() == color) {
208 found = true;
209 }
210
211 m_d->ui->btnRemove->setEnabled(found);
212 m_d->ui->btnTransparent->setEnabled(found);
213
214 if (!found) {
215 KisSignalsBlocker b(m_d->ui->btnTransparent);
216 m_d->ui->btnTransparent->setChecked(false);
217 }
218
219 QModelIndex newIndex = found ? candidateIdx : QModelIndex();
220
221 if (!found) {
222 m_d->ui->colorView->selectionModel()->clear();
223 }
224 if (newIndex.isValid() && newIndex != m_d->ui->colorView->currentIndex()) {
225 m_d->ui->colorView->setCurrentIndex(newIndex);
226 m_d->ui->colorView->update(newIndex);
227 }
228}
229
231{
232 m_d->colorModel->clear(m_d->preferredColumnCount);
233 m_d->transparentColorIndex = -1;
234
235 if (m_d->activeMask) {
236 KisColorizeMask::KeyStrokeColors colors = m_d->activeMask->keyStrokesColors();
237 m_d->transparentColorIndex = colors.transparentIndex;
238
239 for (int i = 0; i < colors.colors.size(); i++) {
240 const QString name = i == m_d->transparentColorIndex ? "transparent" : "";
241 m_d->colorModel->addSwatch(KisSwatch(colors.colors[i], name));
242 }
243 }
244
245 slotCurrentFgColorChanged(m_d->provider->fgColor());
246}
247
249{
250 KisSignalsBlocker b1(m_d->ui->chkAutoUpdates,
251 m_d->ui->btnUpdate,
252 m_d->ui->chkShowKeyStrokes,
253 m_d->ui->chkShowOutput);
254 KisSignalsBlocker b2(m_d->ui->chkUseEdgeDetection,
255 m_d->ui->intEdgeDetectionSize,
256 m_d->ui->intRadius,
257 m_d->ui->intCleanUp,
258 m_d->ui->chkLimitToDevice);
259
260 // not implemented yet!
261 //m_d->ui->chkAutoUpdates->setEnabled(m_d->activeMask);
262 m_d->ui->chkAutoUpdates->setEnabled(false);
263 m_d->ui->chkAutoUpdates->setVisible(false);
264
265 bool value = false;
266
268 m_d->ui->btnUpdate->setEnabled(m_d->activeMask && !m_d->ui->chkAutoUpdates->isChecked() && value);
269
271 m_d->ui->chkShowKeyStrokes->setEnabled(m_d->activeMask);
272 m_d->ui->chkShowKeyStrokes->setChecked(value);
273
275 m_d->ui->chkShowOutput->setEnabled(m_d->activeMask);
276 m_d->ui->chkShowOutput->setChecked(value);
277
278 m_d->ui->chkUseEdgeDetection->setEnabled(m_d->activeMask);
279 m_d->ui->chkUseEdgeDetection->setChecked(m_d->activeMask && m_d->activeMask->useEdgeDetection());
280
281 m_d->ui->intEdgeDetectionSize->setEnabled(m_d->activeMask && m_d->ui->chkUseEdgeDetection->isChecked());
282 m_d->ui->intEdgeDetectionSize->setValue(m_d->activeMask ? m_d->activeMask->edgeDetectionSize() : 4.0);
283 m_d->ui->intRadius->setEnabled(m_d->activeMask);
284 m_d->ui->intRadius->setValue(2 * (m_d->activeMask ? m_d->activeMask->fuzzyRadius() : 15));
285 m_d->ui->intCleanUp->setEnabled(m_d->activeMask);
286 m_d->ui->intCleanUp->setValue(100 * (m_d->activeMask ? m_d->activeMask->cleanUpAmount() : 0.7));
287
288 m_d->ui->chkLimitToDevice->setEnabled(m_d->activeMask);
289 m_d->ui->chkLimitToDevice->setChecked(m_d->activeMask && m_d->activeMask->limitToDeviceBounds());
290}
291
293{
294 m_d->maskSignals.clear();
295
296 KisColorizeMask *mask = dynamic_cast<KisColorizeMask*>(node.data());
297 m_d->activeMask = mask;
298
299 if (m_d->activeMask) {
300 m_d->maskSignals.addConnection(
301 m_d->activeMask, SIGNAL(sigKeyStrokesListChanged()),
302 this, SLOT(slotColorLabelsChanged()));
303
304 m_d->maskSignals.addConnection(
305 m_d->provider->currentImage(), SIGNAL(sigNodeChanged(KisNodeSP)),
306 this, SLOT(slotUpdateNodeProperties()));
307 }
308
311 m_d->ui->colorView->setEnabled(m_d->activeMask);
312}
313
315{
316 KIS_ASSERT_RECOVER_RETURN(m_d->activeMask);
317
318 QModelIndex index = m_d->ui->colorView->currentIndex();
319 KisSwatch activeSwatch = m_d->colorModel->getSwatch(index);
320 if (!index.isValid()) return;
321
323 Q_FOREACH (const QString &groupName, m_d->colorSet->swatchGroupNames()) {
324 KisSwatchGroupSP group = m_d->colorSet->getGroup(groupName);
325 Q_FOREACH (const KisSwatchGroup::SwatchInfo &info, group->infoList()) {
326 infoList.append(info);
327 }
328 }
329
330 // We can't rely on the order of the colors returned, so we need to sort them row by row from left to right
331 std::sort(infoList.begin(), infoList.end(), sortSwatchInfo);
333 int i = 0;
334 for (const KisSwatchGroup::SwatchInfo &info : infoList) {
335 if (activeSwatch == info.swatch && enableTransparency) {
336 colors.transparentIndex = i;
337 }
338 colors.colors << info.swatch.color();
339 i++;
340 }
341
342 m_d->activeMask->setKeyStrokesColors(colors);
343}
344
346{
347 KIS_ASSERT_RECOVER_RETURN(m_d->activeMask);
348
349 QModelIndex index = m_d->ui->colorView->currentIndex();
350 if (!index.isValid()) return;
351
352 const KoColor color = m_d->colorModel->getSwatch(index).color();
353 m_d->activeMask->removeKeyStroke(color);
354}
355
361
363{
364 // not implemented yet!
366}
367
373
379
381{
383 m_d->activeMask->setUseEdgeDetection(value);
384 m_d->ui->intEdgeDetectionSize->setEnabled(value);
385}
386
388{
390 m_d->activeMask->setEdgeDetectionSize(value);
391}
392
394{
396 m_d->activeMask->setFuzzyRadius(0.5 * value);
397}
398
400{
402 m_d->activeMask->setCleanUpAmount(qreal(value) / 100.0);
403}
404
406{
408 m_d->activeMask->setLimitToDeviceBounds(value);
409}
410
411bool KisToolLazyBrushOptionsWidget::sortSwatchInfo(const KisSwatchGroup::SwatchInfo &first, const KisSwatchGroup::SwatchInfo &second)
412{
413 if (first.row < second.row) { return true; }
414 if (first.row > second.row) { return false; }
415 return first.column < second.column;
416}
float value(const T *src, size_t ch)
connect(this, SIGNAL(optionsChanged()), this, SLOT(saveOptions()))
static QVariant nodeProperty(KisNodeSP node, const KoID &id, const QVariant &defaultValue)
static void setNodePropertyAutoUndo(KisNodeSP node, const KoID &id, const QVariant &value, KisImageSP image)
The KisPaletteModel class This, together with KisPaletteView and KisPaletteDelegate forms a mvc way t...
KoColor color() const
Definition KisSwatch.h:30
The KisToolLazyBrushOptionsWidget class.
KisToolLazyBrushOptionsWidget(KisCanvasResourceProvider *provider, QWidget *parent)
const KisSwatchGroup::SwatchInfo & second
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128
#define KIS_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:75
#define ENTER_FUNCTION()
Definition kis_debug.h:178
#define ppVar(var)
Definition kis_debug.h:155
void setText(QSpinBox *spinBox, const QStringView textTemplate)
static KoColorSpaceRegistry * instance()
const KoColorSpace * rgb8(const QString &profileName=QString())
PaletteEventFilter(KisPaletteView *parentView, KisToolLazyBrushOptionsWidget *optionsWidget)
bool eventFilter(QObject *watched, QEvent *event) override
KisToolLazyBrushOptionsWidget * m_optionsWidget