Krita Source Code Documentation
Loading...
Searching...
No Matches
KoDualColorButton.cpp
Go to the documentation of this file.
1/* This file is part of the KDE libraries
2 SPDX-FileCopyrightText: 1999 Daniel M. Duley <mosfet@kde.org>
3 SPDX-FileCopyrightText: 2026 Arkady Flury <arkady.flury@gmail.com>
4
5 SPDX-License-Identifier: LGPL-2.0-only
6*/
7
8#include "KoDualColorButton.h"
9#include "KoColor.h"
11#include <kcolormimedata.h>
12#include <kconfiggroup.h>
13#include <ksharedconfig.h>
14
15#include "dcolorreset.xpm"
16
17#include <QColorDialog>
19
20#include "kis_signals_blocker.h"
21#include <kis_icon.h>
23
24#include <QBrush>
25#include <QDrag>
26#include <QDragEnterEvent>
27#include <QPainter>
28#include <QPointer>
29#include <qdrawutil.h>
30#include <QApplication>
32
34{
35public:
36 Private(const KoColor &fgColor, const KoColor &bgColor,
37 QWidget *_dialogParent,
38 const KoColorDisplayRendererInterface *_displayRenderer)
39 : dialogParent(_dialogParent)
40 , dragFlag( false )
41 , miniCtlFlag( false )
42 , foregroundColor(fgColor)
43 , backgroundColor(bgColor)
44 , displayRenderer(_displayRenderer)
45 {
46 popDialog = true;
47 }
48
49 QWidget* dialogParent;
50
59 std::optional<ColorDialogState> colorDialogState;
60
65
66 void init(KoDualColorButton *q);
67};
68
69
70
72{
73 if ( q->sizeHint().isValid() )
74 q->setMinimumSize( q->sizeHint() );
75
76 q->setAcceptDrops( true );
77 QString caption = i18n("Select a Color");
79 config.modal = false;
81 connect(colorSelectorDialog, &KisDlgInternalColorSelector::finished, q, &KoDualColorButton::slotColorDialogClosed);
82
83}
84
86 const KoColorDisplayRendererInterface *displayRenderer,
87 QWidget *parent, QWidget* dialogParent)
88 : QWidget( parent ),
89 d( new Private(canvasResourceProvider->fgColor(),canvasResourceProvider->bgColor(),
90 dialogParent,
91 displayRenderer) )
92{
93 d->init(this);
94}
95
100
102 resetPixmap = QPixmap( (const char **)dcolorreset_xpm );
103
104 QColor windowText = d->dialogParent->palette().windowText().color();
105
106 arrowBitmap = KisIconUtils::loadIcon("swap_arrow").pixmap(12,12);
107
108 QPainter pen(&arrowBitmap);
109
110 pen.setCompositionMode(QPainter::CompositionMode_SourceIn);
111 pen.fillRect(arrowBitmap.rect(),windowText);
112 pen.end();
113
114 resetArrowPixmap = KisIconUtils::loadIcon("reset_arrow").pixmap(10,12);
115
116 pen.begin(&resetArrowPixmap);
117
118 pen.setCompositionMode(QPainter::CompositionMode_SourceIn);
119 pen.fillRect(resetArrowPixmap.rect(),windowText);
120 pen.end();
121}
122
124 if (d->colorDialogState.has_value()) {
125 d->colorDialogState->selection = state;
126 }
127 d->tmpSelection = state;
128}
129
134
139
141{
142 return d->popDialog;
143}
144
146{
147 return QSize(34, 34);
148}
149
151{
152 d->foregroundColor = color;
153 if (d->colorDialogState && d->colorDialogState->selection == Foreground) {
160 }
161 update();
162}
163
165{
166 d->backgroundColor = color;
167
168 if (d->colorDialogState && d->colorDialogState->selection == Background) {
175 }
176 update();
177}
178
180{
181 if (!displayRenderer) {
182 displayRenderer = KoDumbColorDisplayRenderer::instance();
183 }
184
185 if (displayRenderer == d->displayRenderer) return;
186
187 if (d->displayRenderer) {
188 d->displayRenderer->disconnect(this);
189 }
190
191 d->displayRenderer = displayRenderer;
192
193 if (displayRenderer) {
194 d->displayRenderer = displayRenderer;
195 d->colorSelectorDialog->setDisplayRenderer(displayRenderer);
196
197 connect(d->displayRenderer, SIGNAL(displayConfigurationChanged()), this, SLOT(updateColorSpace()));
199
200 connect(d->displayRenderer, SIGNAL(destroyed()), this, SLOT(setDisplayRenderer()));
201 }
202}
203
205{
206 d->colorSelectorDialog->lockUsedColorSpace(d->displayRenderer->getPaintingColorSpace());
207
208 // we need to update preview tiles, so a paint event is necessary
209 update();
210}
211
213{
214 QColor col;
215 if (d->displayRenderer) {
216 c.convertTo(d->displayRenderer->getPaintingColorSpace());
217 col = d->displayRenderer->toQColor(c);
218 } else {
219 col = c.toQColor();
220 }
221 return col;
222}
223
225{
227}
228
230{
231
232 QPainter painter( this );
233
234 QBrush defBrush = palette().brush( QPalette::Button );
235
236 QBrush foregroundBrush( getColorFromDisplayRenderer(d->foregroundColor), Qt::SolidPattern );
237 QBrush backgroundBrush( getColorFromDisplayRenderer(d->backgroundColor), Qt::SolidPattern );
238
239 if (resetColours) {
240 foregroundBrush = Qt::black;
241 backgroundBrush = Qt::white;
242 }
243
244 qDrawShadeRect( &painter, backgroundRect, palette(), false, 1, 0,
245 isEnabled() ? &backgroundBrush : &defBrush );
246
247 qDrawShadeRect( &painter, foregroundRect, palette(), false, 1, 0,
248 isEnabled() ? &foregroundBrush : &defBrush );
249
250 painter.setPen( palette().color( QPalette::Shadow ) );
251
252 paint_icons(painter);
253}
254
255void KoDualColorButton::paint_icons(QPainter &painter){
256 painter.drawPixmap( foregroundRect.right() + 2, 1, arrowBitmap );
257 painter.drawPixmap( 1, foregroundRect.bottom() + 2, resetPixmap );
258}
259
260
261void KoDualColorButton::dragEnterEvent( QDragEnterEvent *event )
262{
263 event->setAccepted( isEnabled() && KColorMimeData::canDecode( event->mimeData() ) );
264}
265
266void KoDualColorButton::dropEvent( QDropEvent *event )
267{
268 Q_UNUSED(event);
269}
270
277
284
286{
287 d->colorDialogState = std::nullopt;
288}
289
291{
292 d->colorDialogState.emplace();
293 d->colorDialogState->selection = Foreground;
294 // TODO: fix cyclic connections in a proper way
295 d->colorDialogState->connections.addUniqueConnection(d->colorSelectorDialog, SIGNAL(signalForegroundColorChosen(KoColor)), this, SLOT(slotSetForegroundColorFromDialog(KoColor)));
296 d->colorDialogState->connections.addUniqueConnection(this, SIGNAL(foregroundColorChanged(KoColor)), d->colorSelectorDialog, SLOT(slotColorUpdated(KoColor)));
299 d->colorSelectorDialog->show();
300 update();
301}
302
304{
305 d->colorDialogState.emplace();
306 d->colorDialogState->selection = Background;
307 // TODO: fix cyclic connections in a proper way
308 d->colorDialogState->connections.addUniqueConnection(d->colorSelectorDialog, SIGNAL(signalForegroundColorChosen(KoColor)), this, SLOT(slotSetBackgroundColorFromDialog(KoColor)));
309 d->colorDialogState->connections.addUniqueConnection(this, SIGNAL(backgroundColorChanged(KoColor)), d->colorSelectorDialog, SLOT(slotColorUpdated(KoColor)));
312 d->colorSelectorDialog->show();
313 update();
314}
315
316void KoDualColorButton::backgroundSelect(bool usePlatformDialog)
317{
318 if( d->popDialog) {
319 if (usePlatformDialog) {
320 QColor c = d->backgroundColor.toQColor();
321 c = QColorDialog::getColor(c, this);
322 if (c.isValid()) {
323 d->backgroundColor = d->displayRenderer->approximateFromRenderedQColor(c);
325 }
326 }
327 else {
329 }
330 }
331}
332
333void KoDualColorButton::foregroundSelect(bool usePlatformDialog)
334{
335 if( d->popDialog) {
336 if (usePlatformDialog) {
337 QColor c = d->foregroundColor.toQColor();
338 c = QColorDialog::getColor(c, this);
339 if (c.isValid()) {
340 d->foregroundColor = d->displayRenderer->approximateFromRenderedQColor(c);
342 }
343 }
344 else {
346 }
347 }
348}
349
350void KoDualColorButton::mousePressEvent( QMouseEvent *event )
351{
352
353 d->dragPosition = event->pos();
354
355 d->dragFlag = false;
356
357 if ( foregroundRect.contains( d->dragPosition ) ) {
359 d->miniCtlFlag = false;
360 }
361 else if( backgroundRect.contains( d->dragPosition ) ) {
363 d->miniCtlFlag = false;
364 }
365 else if ( event->pos().x() > foregroundRect.width() ) {
366 swapColours();
367
368 d->miniCtlFlag = true;
369 }
370 else if ( event->pos().x() < backgroundRect.x() ) {
371 ResetColours();
372
373 d->miniCtlFlag = true;
374 }
375 update();
376}
377
378
380{
381 d->foregroundColor = d->displayRenderer->approximateFromRenderedQColor(Qt::black);
382 d->backgroundColor = d->displayRenderer->approximateFromRenderedQColor(Qt::white);
383
386}
387
397
398void KoDualColorButton::mouseMoveEvent( QMouseEvent *event )
399{
400 if ( !d->miniCtlFlag ) {
401 int delay = QApplication::startDragDistance();
402
403 if ( event->x() >= d->dragPosition.x() + delay || event->x() <= d->dragPosition.x() - delay ||
404 event->y() >= d->dragPosition.y() + delay || event->y() <= d->dragPosition.y() - delay ) {
405 KColorMimeData::createDrag( d->tmpSelection == Foreground ?
408 this )->exec();
409 d->dragFlag = true;
410 }
411 }
412}
413
414void KoDualColorButton::mouseReleaseEvent( QMouseEvent *event )
415{
416 d->dragFlag = false;
417
418 if ( d->miniCtlFlag )
419 return;
420
421 d->miniCtlFlag = false;
422
423
424 KConfigGroup cfg = KSharedConfig::openConfig()->group("colorselector");
425 bool usePlatformDialog = cfg.readEntry("UsePlatformColorDialog", false);
426
427 if (foregroundRect.contains( event->pos())) {
428 if (d->tmpSelection == Foreground) {
429 foregroundSelect(usePlatformDialog);
430 }
431 else {
434 }
435 }
436 else if (backgroundRect.contains( event->pos())) {
437 if(d->tmpSelection == Background ) {
438 backgroundSelect(usePlatformDialog);
439 } else {
442 }
443 }
444
445 update();
446}
447
448
449
450
452{
453 QWidget::changeEvent(event);
454
455 switch (event->type()) {
456 case QEvent::StyleChange:
457 case QEvent::PaletteChange:
458 updateArrows();
459 default:
460 break;
461 }
462}
463
464bool KoDualColorButton::event(QEvent *event)
465{
466 if (event->type() == QEvent::ToolTip) {
467
468 const QHelpEvent *helpEvent = static_cast<QHelpEvent*>(event);
469
470 if (this->mapFromGlobal(helpEvent->globalPos()).x() < backgroundRect.x() ) {
471 if (this->mapFromGlobal(helpEvent->globalPos()).y() < backgroundRect.y()){
472 this->setToolTip(i18n("Foreground color selector"));
473 }
474 else{
475 this->setToolTip(i18n("Set foreground and background colors to black and white"));
476 }
477 }
478 else {
479 if (this->mapFromGlobal(helpEvent->globalPos()).y() < backgroundRect.y() ) {
480 this->setToolTip(i18n("Swap foreground and background colors"));
481 }
482 else{
483 this->setToolTip(i18n("Background color selector"));
484 }
485 }
486 }
487 return QWidget::event(event);
488
489}
490
The KisInternalColorSelector class.
void setPreviousColor(KoColor c)
setPreviousColor set the previous color.
void setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer)
setDisplayRenderer Set the display renderer. This is necessary for HDR color manage support.
void lockUsedColorSpace(const KoColorSpace *cs)
lockUsedColorSpace Lock the used colorspace of this selector.
void slotColorUpdated(KoColor newColor)
slotColorUpdated Very important slot. Is connected to krita's resources to make sure it has the curre...
void convertTo(const KoColorSpace *cs, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags)
Definition KoColor.cpp:136
void toQColor(QColor *c) const
a convenience method for the above.
Definition KoColor.cpp:198
Private(const KoColor &fgColor, const KoColor &bgColor, QWidget *_dialogParent, const KoColorDisplayRendererInterface *_displayRenderer)
KisDlgInternalColorSelector * colorSelectorDialog
QPointer< const KoColorDisplayRendererInterface > displayRenderer
std::optional< ColorDialogState > colorDialogState
void init(KoDualColorButton *q)
A widget for selecting two related colors.
void setForegroundColor(const KoColor &color)
KoDualColorButton(KisCanvasResourceProvider *canvasResourceProvider, const KoColorDisplayRendererInterface *displayRenderer, QWidget *parent=0, QWidget *dialogParent=0)
virtual void mouseMoveEvent(QMouseEvent *event) override
void slotSetBackgroundColorFromDialog(const KoColor color)
virtual void paint_icons(QPainter &painter)
bool event(QEvent *event) override
void paintEvent(QPaintEvent *event) override
void setPopDialog(bool popDialog)
void setColorDialogState(Selection state)
QSize sizeHint() const override
void backgroundSelect(bool usePlatformDialog)
void dragEnterEvent(QDragEnterEvent *event) override
void updateColorSpace()
updateColorSpace() from the current display renderer set ColorSpace so we can lock the selector....
void foregroundColorChanged(const KoColor &color)
void slotSetForegroundColorFromDialog(const KoColor color)
QColor getColorFromDisplayRenderer(KoColor c)
getColorFromDisplayRenderer convenience function to get the right qcolor from the display renderer,...
virtual void mousePressEvent(QMouseEvent *event) override
void backgroundColorChanged(const KoColor &color)
virtual void mouseReleaseEvent(QMouseEvent *event) override
void setDisplayRenderer(const KoColorDisplayRendererInterface *displayRenderer=KoDumbColorDisplayRenderer::instance())
void setBackgroundColor(const KoColor &color)
void foregroundSelect(bool usePlatformDialog)
void dropEvent(QDropEvent *event) override
void changeEvent(QEvent *event) override
static KoColorDisplayRendererInterface * instance()
QIcon loadIcon(const QString &name)