Krita Source Code Documentation
Loading...
Searching...
No Matches
WGColorSelectorDock.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2020 Mathias Wein <lynx.mw+kde@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-3.0-or-later
5 */
6
8
9#include "KisDocument.h"
10#include "WGActionManager.h"
12#include "WGColorPatches.h"
14#include "WGCommonColorSet.h"
17#include "WGShadeSelector.h"
20
21#include <klocalizedstring.h>
22
23#include <kis_icon.h>
24#include <kis_canvas2.h>
26#include <kis_config_notifier.h>
29#include <KisUniqueColorSet.h>
30#include <KisGamutMaskToolbar.h>
32
33#include <QBoxLayout>
34#include <QMenu>
35#include <QToolButton>
36#include <QWidgetAction>
37
38#include <QDebug>
39#include <kis_assert.h>
40
42 : QDockWidget()
43 , m_displayConfig(new WGSelectorDisplayConfig)
44 , m_colorChangeCompressor(new KisSignalCompressor(100 /* ms */, KisSignalCompressor::POSTPONE, this))
45 , m_actionManager(new WGActionManager(this))
46 , m_colorTooltip(new WGColorPreviewToolTip(this))
47 , m_colorModelBG(new KisVisualColorModel)
48 , m_mainWidget(new QWidget())
49{
50 setWindowTitle(i18n("Wide Gamut Color Selector"));
51
52 QWidget *mainWidget = m_mainWidget;
53 mainWidget->installEventFilter(this);
54
55 m_mainWidgetLayout = new QVBoxLayout(mainWidget);
56 m_verticalElementsLayout = new QHBoxLayout();
57 m_selectorAreaLayout = new QBoxLayout(QBoxLayout::TopToBottom);
58
59 m_selector = new KisVisualColorSelector(mainWidget);
61 connect(m_selector, SIGNAL(sigNewColor(KoColor)), SLOT(slotColorSelected(KoColor)));
62 connect(m_selector, SIGNAL(sigInteraction(bool)), SLOT(slotColorInteraction(bool)));
63 connect(m_colorChangeCompressor, SIGNAL(timeout()), SLOT(slotSetNewColors()));
65
66 // Header
67 QWidget *headerWidget = new QWidget(mainWidget);
68 QHBoxLayout *headerLayout = new QHBoxLayout(headerWidget);
69
70 m_toggle = new KisColorSourceToggle(mainWidget);
71 connect(m_toggle, SIGNAL(toggled(bool)), SLOT(slotColorSourceToggled(bool)));
72 headerLayout->addWidget(m_toggle);
74 m_gamutToolbar->setContentsMargins(0, 0, 0, 5);
75 m_gamutToolbar->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Minimum);
76 headerLayout->addWidget(m_gamutToolbar);
77 headerLayout->addStretch();
78 headerLayout->setContentsMargins(0, 0, 0, 0);
79
80 connect(m_selector, SIGNAL(sigGamutMaskSupportChanged(bool)), SLOT(slotShowGamutMaskToolbar(bool)));
81
82 m_configButton = new QToolButton(this);
83 m_configButton->setIcon(KisIconUtils::loadIcon("view-choose"));
84 m_configButton->setAutoRaise(true);
85 m_configButton->setPopupMode(QToolButton::InstantPopup);
86 headerLayout->addWidget(m_configButton);
87
88 m_mainWidgetLayout->addWidget(headerWidget);
91
93
97 connect(m_shadeSelector, SIGNAL(sigColorInteraction(bool)), SLOT(slotColorInteraction(bool)));
98
99 // eventually it should made be a global history, not specific to any plugin
103
106 connect(m_history, SIGNAL(sigColorChanged(KoColor)), SLOT(slotColorSelected(KoColor)));
107 connect(m_history, SIGNAL(sigColorInteraction(bool)), SLOT(slotColorInteraction(bool)));
108
109 // Common Colors (Colors from Image)
111
114 connect(m_commonColors, SIGNAL(sigColorChanged(KoColor)), SLOT(slotColorSelected(KoColor)));
115 connect(m_commonColors, SIGNAL(sigColorInteraction(bool)), SLOT(slotColorInteraction(bool)));
116
117 connect(WGConfig::notifier(), SIGNAL(configChanged()), SLOT(slotConfigurationChanged()));
118
119 setWidget(mainWidget);
121 setEnabled(false);
122}
123
125{
126 // currently always return foreground model;
127 // do lazy conversion to current HSX model if required
128 if (selectingBackground() && m_colorModelBG->isHSXModel()) {
129 m_colorModelFG->setRGBColorModel(m_colorModelBG->colorModel());
130 }
131 return *(m_colorModelFG);
132}
133
135{
136 KisDisplayColorConverter *converter = nullptr;
137 if (m_canvas) {
138 converter = m_canvas->displayColorConverter();
139 }
140 return (rawPointer || converter) ? converter : KisDisplayColorConverter::dumbConverterInstance();
141}
142
144{
145 return m_toggle->isChecked();
146}
147
148void WGColorSelectorDock::setChannelValues(const QVector4D &values)
149{
150 // currently always set foreground color
151 if (!m_canvas) {
152 return;
153 }
154
155 // This could be nicer...if setting active model, this triggers slotColorSelected()
156 // and leaves timer running with NOP, otherwise the resource update is detected as
157 // external event and updates UI.
158 m_colorModelFG->slotSetChannelValues(values);
159
160 m_canvas->resourceManager()->setForegroundColor(m_colorModelFG->currentColor());
161 m_pendingFgUpdate = false;
162}
163
169
171{
172 if (m_canvas.data() == canvas)
173 {
174 // not sure why setCanvas gets called 3 times for new canvas, just skip
175 return;
176 }
177 if (m_canvas) {
179 }
180 m_actionManager->setCanvas(qobject_cast<KisCanvas2*>(canvas), m_canvas);
181 m_canvas = qobject_cast<KisCanvas2*>(canvas);
182 // TODO: unset display converters if canvas is null
183 if (m_canvas) {
184 KoColorDisplayRendererInterface *dri = m_canvas->displayColorConverter()->displayRendererInterface();
185 KisCanvasResourceProvider *resourceProvider = m_canvas->imageView()->resourceProvider();
186
187 m_globalColorHistoryModel = resourceProvider->colorHistoryModel();
188 m_documentColorHistoryModel = m_canvas->imageView()->document()->colorHistoryModel();
189
192
194 m_displayConfig->setDisplayConverter(m_canvas->displayColorConverter());
196 //m_toggle->setBackgroundColor(dri->toQColor(color));
197 connect(dri, SIGNAL(displayConfigurationChanged()), this, SLOT(slotDisplayConfigurationChanged()));
198 connect(m_canvas->resourceManager(), SIGNAL(canvasResourceChanged(int,QVariant)),
199 this, SLOT(slotCanvasResourceChanged(int,QVariant)));
200 connect(resourceProvider, SIGNAL(sigFGColorUsed(KoColor)),
201 this, SLOT(slotFGColorUsed(KoColor)), Qt::UniqueConnection);
202
203 // Gamut Mask
204 connect(resourceProvider, SIGNAL(sigGamutMaskChanged(KoGamutMaskSP)),
205 m_selector, SLOT(slotGamutMaskChanged(KoGamutMaskSP)), Qt::UniqueConnection);
206
207 connect(resourceProvider, SIGNAL(sigGamutMaskPreviewUpdate()),
208 m_selector, SLOT(slotGamutMaskPreviewUpdate()), Qt::UniqueConnection);
209
210 connect(resourceProvider, SIGNAL(sigGamutMaskUnset()),
211 m_selector, SLOT(slotGamutMaskUnset()), Qt::UniqueConnection);
212
213 connect(resourceProvider, SIGNAL(sigGamutMaskDeactivated()),
214 m_selector, SLOT(slotGamutMaskUnset()), Qt::UniqueConnection);
215
216 m_gamutToolbar->connectMaskSignals(resourceProvider);
217
218 // quirk note: displayConfigurationChanged signal gets sent *before* the new canvas gets
219 // passed, through the display converter of the now inactive canvas! So we need to repeat...
221 }
222 setEnabled(canvas != 0);
223}
224
237
242
244{
245 m_canvas->disconnectCanvasObserver(this);
246 m_canvas->displayColorConverter()->displayRendererInterface()->disconnect(this);
247 m_canvas->imageView()->resourceProvider()->disconnect(m_selector);
248 m_canvas = 0;
249}
250
252{
254
255 bool historyEnabled = cfg.get(WGConfig::colorHistoryEnabled);
256 Qt::Orientation historyOrientation = cfg.get(WGConfig::colorHistory.orientation);
257
258 m_verticalElementsLayout->removeWidget(m_history);
260 m_mainWidgetLayout->removeWidget(m_history);
261 m_mainWidgetLayout->removeWidget(m_commonColors);
262
263 if (historyEnabled) {
264 if (historyOrientation == Qt::Vertical) {
266 }
267 else {
268 m_mainWidgetLayout->addWidget(m_history);
269 }
270 m_history->show();
271 }
272 else {
273 m_history->hide();
274 }
275
276 bool commonColorsEnabled = cfg.get(WGConfig::commonColorsEnabled);
277 Qt::Orientation commonColorsOrientation = cfg.get(WGConfig::commonColors.orientation);
278
279 if (commonColorsEnabled) {
280 if (commonColorsOrientation == Qt::Vertical) {
282 }
283 else {
285 }
286 m_commonColors->show();
287 }
288 else {
289 m_commonColors->hide();
290 }
291
292 bool shadeSelectorEnabled = cfg.get(WGConfig::minimalShadeSelectorEnabled);
293 if (shadeSelectorEnabled) {
294 m_shadeSelector->show();
295 }
296 else {
297 m_shadeSelector->hide();
298 }
299
300}
301
303{
306 m_selector->selectorModel()->setRGBColorModel(cfg.get(WGConfig::rgbColorModel));
307 KisColorSelectorConfiguration selectorCfg = cfg.colorSelectorConfiguration();
308 m_selector->setConfiguration(&selectorCfg);
311 m_customCS = cfg.customSelectionColorSpace();
312 }
313 bool proofColors = cfg.get(WGConfig::proofToPaintingColors);
314 m_selector->setProofColors(proofColors);
315 m_displayConfig->setPreviewInPaintingCS(proofColors);
317
322
325 // Quick settings menu
326 if (cfg.get(WGConfig::quickSettingsEnabled)) {
327 if (!m_configButton->menu()) {
328 m_configButton->disconnect(this);
329 QMenu *configureMenu = new QMenu(this);
331 // prevents hover indicator being stuck on other menu entries
332 m_quickSettings->setMouseTracking(true);
333 m_quickSettingAction = new QWidgetAction(this);
334 m_quickSettingAction->setDefaultWidget(m_quickSettings);
335
336 configureMenu->addAction(m_quickSettingAction);
337 QAction *cfgAction = configureMenu->addAction(i18nc("Wide Gamut Color Selector", "Configure..."));
338 connect(cfgAction, SIGNAL(triggered(bool)), SLOT(slotOpenSettings()));
339 m_configButton->setMenu(configureMenu);
340 } else {
341 // WORKAROUND: force geometry update by re-adding action, all other attempts failed...
342 QMenu *menu = m_configButton->menu();
343 menu->removeAction(m_quickSettingAction);
344 menu->insertAction(menu->actions().constFirst(), m_quickSettingAction);
345 }
347 } else {
348 if (m_configButton->menu()) {
349 m_configButton->menu()->deleteLater();
350 m_configButton->setMenu(0);
353 m_quickSettings = 0;
354 }
355 connect(m_configButton, SIGNAL(clicked(bool)), SLOT(slotOpenSettings()), Qt::UniqueConnection);
356 }
357
358 updateLayout();
359
360 if (m_canvas) {
362 }
363}
364
366{
367 if (!m_canvas) {
368 return;
369 }
370
371 const KoColorSpace *selectionCS = nullptr;
372
373 // Note: displayConfigurationChanged is also emitted on image color space changes,
374 // so there's no need to handle extra signals, although it's a bit convoluted
376 selectionCS = m_canvas->image()->colorSpace();
377 } else if (m_CSSource == FixedColorSpace) {
378 selectionCS = m_customCS;
379 } else {
380 selectionCS = m_canvas->displayColorConverter()->nodeColorSpace();
381 }
382
383 // TODO: use m_viewManager->canvasResourceProvider()->fgColor();
384 KoColor fgColor = m_canvas->resourceManager()->foregroundColor();
385 KoColor bgColor = m_canvas->resourceManager()->backgroundColor();
386
387 bool proof = m_displayConfig->previewInPaintingCS();
388 m_toggle->setForegroundColor(displayColorConverter()->toQColor(fgColor, proof));
389 m_toggle->setBackgroundColor(displayColorConverter()->toQColor(bgColor, proof));
391
392 if (selectionCS && selectionCS != activeModel->colorSpace()) {
393 activeModel->slotSetColorSpace(selectionCS);
394 activeModel->slotSetColor(activeModel == m_colorModelFG ? fgColor : bgColor);
395 }
396}
397
399{
400 QColor displayCol = displayColorConverter()->toQColor(color, m_displayConfig->previewInPaintingCS());
401 m_colorTooltip->setCurrentColor(displayCol);
402 if (selectingBackground()) {
403 m_toggle->setBackgroundColor(displayCol);
404 m_pendingBgUpdate = true;
406 }
407 else {
408 m_toggle->setForegroundColor(displayCol);
409 m_pendingFgUpdate = true;
411 }
412 if (sender() != m_selector) {
413 m_selector->slotSetColor(color);
414 }
415}
416
418{
419 if (selectingBg) {
420 if (m_colorModelFG->isHSXModel()) {
421 m_colorModelBG->setRGBColorModel(m_colorModelFG->colorModel());
422 }
425 }
426 else {
427 if (m_colorModelBG->isHSXModel()) {
428 m_colorModelFG->setRGBColorModel(m_colorModelBG->colorModel());
429 }
432 }
433 // currently, only the color space of the active model is updated, so it may be outdated
434 if (m_canvas) {
436 }
437}
438
440{
441 if (active) {
442 QColor baseCol = m_displayConfig->displayConverter()->toQColor(m_selector->getCurrentColor());
445 if (sender() == m_shadeSelector) {
447 } else {
449 }
450 }
451}
452
454{
455 QColor lastCol = m_displayConfig->displayConverter()->toQColor(color);
460 } else {
462 }
463}
464
466{
467 //KIS_SAFE_ASSERT_RECOVER_RETURN(m_pendingFgUpdate || m_pendingBgUpdate);
468 if (m_pendingFgUpdate) {
469 m_canvas->resourceManager()->setForegroundColor(m_colorModelFG->currentColor());
470 m_pendingFgUpdate = false;
471 }
472 if (m_pendingBgUpdate) {
473 m_canvas->resourceManager()->setBackgroundColor(m_colorModelBG->currentColor());
474 m_pendingBgUpdate = false;
475 }
476}
477
479{
480 switch (key) {
482 if (!m_pendingFgUpdate) {
483 KoColor color = value.value<KoColor>();
485 m_colorModelFG->slotSetColor(color);
486 }
487 break;
489 if (!m_pendingBgUpdate) {
490 KoColor color = value.value<KoColor>();
492 m_colorModelBG->slotSetColor(color);
493 }
494 default:
495 break;
496 }
497}
498
500{
501 if (!m_canvas) return;
502
504 if (settings.exec() == QDialog::Accepted) {
505 //WGConfig::notifier()->notifyConfigChanged();
506 }
507}
508
510{
511 m_gamutToolbar->setVisible(show);
512}
513
514bool WGColorSelectorDock::eventFilter(QObject *obj, QEvent *e)
515{
516 Q_UNUSED(obj);
517
518 // Get the leave event of the inner widget, for when the docker is borrowed and doesn't properly handle leave events
519 if (e->type() == QEvent::Leave) {
520 m_colorTooltip->hide();
521 }
522
523 return false;
524}
525
526namespace WGConfig {
532}
float value(const T *src, size_t ch)
KisUniqueColorSet * colorHistoryModel() const
void setBackgroundColor(const QColor &color)
void setForegroundColor(const QColor &color)
static KisDisplayColorConverter * dumbConverterInstance()
QColor toQColor(const KoColor &c, bool proofToPaintColors=false) const
void connectMaskSignals(KisCanvasResourceProvider *resourceProvider)
void addColor(const KoColor &color)
The KisVisualColorModel class allows manipulating a KoColor using various color models.
The KisVisualColorSelector class.
void setSelectorModel(KisVisualColorModelSP model)
void setRenderMode(RenderMode mode)
void setConfiguration(const KisColorSelectorConfiguration *config)
Explicitly set the shape configuration. Accepts all valid combinations of Advanced Color Selector,...
void setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer) override
void slotSetColor(const KoColor &c) override
KoColor getCurrentColor() const override
KisVisualColorModelSP selectorModel() const
void setCanvas(KisCanvas2 *canvas, KisCanvas2 *oldCanvas)
void setLastUsedColor(const KoColor &col)
void registerActions(KisViewManager *viewManager)
void setColorHistoryModel(KisUniqueColorSet *history)
void setPreset(Preset preset)
void updateSettings() override
void setLastUsedColor(const QColor &color)
void show(const QWidget *focus=nullptr)
void setCurrentColor(const QColor &color)
void setPreviousColor(const QColor &color)
const KoColorSpace * m_customCS
void slotColorSelected(const KoColor &color)
void setViewManager(KisViewManager *viewManager) override
WGQuickSettingsWidget * m_quickSettings
QBoxLayout * m_selectorAreaLayout
bool eventFilter(QObject *obj, QEvent *ev) override
KisGamutMaskToolbar * m_gamutToolbar
void slotShowGamutMaskToolbar(bool show)
void slotColorInteraction(bool active)
WGCommonColorSet * m_commonColorSet
WGShadeSelector * m_shadeSelector
KisVisualColorModelSP m_colorModelBG
QWidgetAction * m_quickSettingAction
KisColorSourceToggle * m_toggle
QBoxLayout * m_mainWidgetLayout
void slotColorSourceToggled(bool selectingBg)
WGColorPatches * m_history
KisUniqueColorSet * colorHistoryModel() const
void slotFGColorUsed(const KoColor &color)
const KisVisualColorModel & colorModel() const
WGActionManager * m_actionManager
KisSignalCompressor * m_colorChangeCompressor
KisVisualColorModelSP m_colorModelFG
void setCanvas(KoCanvasBase *canvas) override
KisUniqueColorSet * m_documentColorHistoryModel
void slotCanvasResourceChanged(int key, const QVariant &value)
std::unique_ptr< KisUniqueColorSet > m_fallbackColorHistoryModel
KisVisualColorSelector * m_selector
QBoxLayout * m_verticalElementsLayout
KisDisplayColorConverter * displayColorConverter(bool rawPointer=false) const
KisUniqueColorSet * m_globalColorHistoryModel
void setChannelValues(const QVector4D &values)
Set new channel values; takes effect immediately!
ColorSpaceSource m_CSSource
WGColorPatches * m_commonColors
WGSelectorDisplayConfigSP m_displayConfig
QPointer< KisCanvas2 > m_canvas
WGColorPreviewToolTip * m_colorTooltip
void setAutoUpdate(bool enabled)
void setImage(KisImageSP image)
void setModel(KisVisualColorModelSP colorModel) override
void updateSettings() override
KisSharedPtr< KisImage > KisImageSP
Definition kis_types.h:69
QIcon loadIcon(const QString &name)
@ BackgroundColor
The active background color selected for this canvas.
@ ForegroundColor
The active foreground color selected for this canvas.
const GenericSetting< bool > colorHistoryEnabled
Definition WGConfig.cpp:238
const ColorPatches commonColors
Definition WGConfig.cpp:221
const GenericSetting< bool > colorHistoryFromDocument
Definition WGConfig.cpp:239
const GenericSetting< bool > minimalShadeSelectorEnabled
Definition WGConfig.cpp:247
const GenericSetting< bool > commonColorsEnabled
Definition WGConfig.cpp:240
const NumericSetting< KisVisualColorSelector::RenderMode > selectorRenderMode
Definition WGConfig.cpp:256
const NumericSetting< WGColorSelectorDock::ColorSpaceSource > colorSpaceSource
WGConfigNotifier * notifier()
Definition WGConfig.cpp:190
const NumericSetting< KisVisualColorModel::ColorModel > rgbColorModel
Definition WGConfig.cpp:253
class WGConfig Accessor
const GenericSetting< bool > proofToPaintingColors
Definition WGConfig.cpp:237
const GenericSetting< bool > quickSettingsEnabled
Definition WGConfig.cpp:244
const GenericSetting< bool > commonColorsAutoUpdate
Definition WGConfig.cpp:242
const ColorPatches colorHistory
Definition WGConfig.cpp:213