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{
182 d->displayRenderer->disconnect(this);
183 }
184 if (displayRenderer) {
185 d->displayRenderer = displayRenderer;
186 d->colorSelectorDialog->setDisplayRenderer(displayRenderer);
187 connect(d->displayRenderer, SIGNAL(destroyed()), this, SLOT(setDisplayRenderer()), Qt::UniqueConnection);
188 connect(d->displayRenderer, SIGNAL(displayConfigurationChanged()), this, SLOT(update()));
189 } else {
191 }
192}
193
198
200{
201 QColor col;
202 if (d->displayRenderer) {
203 c.convertTo(d->displayRenderer->getPaintingColorSpace());
204 col = d->displayRenderer->toQColor(c);
205 } else {
206 col = c.toQColor();
207 }
208 return col;
209}
210
212{
214}
215
217{
218
219 QPainter painter( this );
220
221 QBrush defBrush = palette().brush( QPalette::Button );
222
223 QBrush foregroundBrush( getColorFromDisplayRenderer(d->foregroundColor), Qt::SolidPattern );
224 QBrush backgroundBrush( getColorFromDisplayRenderer(d->backgroundColor), Qt::SolidPattern );
225
226 if (resetColours) {
227 foregroundBrush = Qt::black;
228 backgroundBrush = Qt::white;
229 }
230
231 qDrawShadeRect( &painter, backgroundRect, palette(), false, 1, 0,
232 isEnabled() ? &backgroundBrush : &defBrush );
233
234 qDrawShadeRect( &painter, foregroundRect, palette(), false, 1, 0,
235 isEnabled() ? &foregroundBrush : &defBrush );
236
237 painter.setPen( palette().color( QPalette::Shadow ) );
238
239 paint_icons(painter);
240}
241
242void KoDualColorButton::paint_icons(QPainter &painter){
243 painter.drawPixmap( foregroundRect.right() + 2, 1, arrowBitmap );
244 painter.drawPixmap( 1, foregroundRect.bottom() + 2, resetPixmap );
245}
246
247
248void KoDualColorButton::dragEnterEvent( QDragEnterEvent *event )
249{
250 event->setAccepted( isEnabled() && KColorMimeData::canDecode( event->mimeData() ) );
251}
252
253void KoDualColorButton::dropEvent( QDropEvent *event )
254{
255 Q_UNUSED(event);
256}
257
264
271
273{
274 d->colorDialogState = std::nullopt;
275}
276
278{
279 d->colorDialogState.emplace();
280 d->colorDialogState->selection = Foreground;
281 // TODO: fix cyclic connections in a proper way
282 d->colorDialogState->connections.addUniqueConnection(d->colorSelectorDialog, SIGNAL(signalForegroundColorChosen(KoColor)), this, SLOT(slotSetForegroundColorFromDialog(KoColor)));
283 d->colorDialogState->connections.addUniqueConnection(this, SIGNAL(foregroundColorChanged(KoColor)), d->colorSelectorDialog, SLOT(slotColorUpdated(KoColor)));
286 d->colorSelectorDialog->show();
287 update();
288}
289
291{
292 d->colorDialogState.emplace();
293 d->colorDialogState->selection = Background;
294 // TODO: fix cyclic connections in a proper way
295 d->colorDialogState->connections.addUniqueConnection(d->colorSelectorDialog, SIGNAL(signalForegroundColorChosen(KoColor)), this, SLOT(slotSetBackgroundColorFromDialog(KoColor)));
296 d->colorDialogState->connections.addUniqueConnection(this, SIGNAL(backgroundColorChanged(KoColor)), d->colorSelectorDialog, SLOT(slotColorUpdated(KoColor)));
299 d->colorSelectorDialog->show();
300 update();
301}
302
303void KoDualColorButton::backgroundSelect(bool usePlatformDialog)
304{
305 if( d->popDialog) {
306 if (usePlatformDialog) {
307 QColor c = d->backgroundColor.toQColor();
308 c = QColorDialog::getColor(c, this);
309 if (c.isValid()) {
310 d->backgroundColor = d->displayRenderer->approximateFromRenderedQColor(c);
312 }
313 }
314 else {
316 }
317 }
318}
319
320void KoDualColorButton::foregroundSelect(bool usePlatformDialog)
321{
322 if( d->popDialog) {
323 if (usePlatformDialog) {
324 QColor c = d->foregroundColor.toQColor();
325 c = QColorDialog::getColor(c, this);
326 if (c.isValid()) {
327 d->foregroundColor = d->displayRenderer->approximateFromRenderedQColor(c);
329 }
330 }
331 else {
333 }
334 }
335}
336
337void KoDualColorButton::mousePressEvent( QMouseEvent *event )
338{
339
340 d->dragPosition = event->pos();
341
342 d->dragFlag = false;
343
344 if ( foregroundRect.contains( d->dragPosition ) ) {
346 d->miniCtlFlag = false;
347 }
348 else if( backgroundRect.contains( d->dragPosition ) ) {
350 d->miniCtlFlag = false;
351 }
352 else if ( event->pos().x() > foregroundRect.width() ) {
353 swapColours();
354
355 d->miniCtlFlag = true;
356 }
357 else if ( event->pos().x() < backgroundRect.x() ) {
358 ResetColours();
359
360 d->miniCtlFlag = true;
361 }
362 update();
363}
364
365
367{
368 d->foregroundColor = d->displayRenderer->approximateFromRenderedQColor(Qt::black);
369 d->backgroundColor = d->displayRenderer->approximateFromRenderedQColor(Qt::white);
370
373}
374
384
385void KoDualColorButton::mouseMoveEvent( QMouseEvent *event )
386{
387 if ( !d->miniCtlFlag ) {
388 int delay = QApplication::startDragDistance();
389
390 if ( event->x() >= d->dragPosition.x() + delay || event->x() <= d->dragPosition.x() - delay ||
391 event->y() >= d->dragPosition.y() + delay || event->y() <= d->dragPosition.y() - delay ) {
392 KColorMimeData::createDrag( d->tmpSelection == Foreground ?
395 this )->exec();
396 d->dragFlag = true;
397 }
398 }
399}
400
401void KoDualColorButton::mouseReleaseEvent( QMouseEvent *event )
402{
403 d->dragFlag = false;
404
405 if ( d->miniCtlFlag )
406 return;
407
408 d->miniCtlFlag = false;
409
410
411 KConfigGroup cfg = KSharedConfig::openConfig()->group("colorselector");
412 bool usePlatformDialog = cfg.readEntry("UsePlatformColorDialog", false);
413
414 if (foregroundRect.contains( event->pos())) {
415 if (d->tmpSelection == Foreground) {
416 foregroundSelect(usePlatformDialog);
417 }
418 else {
421 }
422 }
423 else if (backgroundRect.contains( event->pos())) {
424 if(d->tmpSelection == Background ) {
425 backgroundSelect(usePlatformDialog);
426 } else {
429 }
430 }
431
432 update();
433}
434
435
436
437
439{
440 QWidget::changeEvent(event);
441
442 switch (event->type()) {
443 case QEvent::StyleChange:
444 case QEvent::PaletteChange:
445 updateArrows();
446 default:
447 break;
448 }
449}
450
451bool KoDualColorButton::event(QEvent *event)
452{
453 if (event->type() == QEvent::ToolTip) {
454
455 const QHelpEvent *helpEvent = static_cast<QHelpEvent*>(event);
456
457 if (this->mapFromGlobal(helpEvent->globalPos()).x() < backgroundRect.x() ) {
458 if (this->mapFromGlobal(helpEvent->globalPos()).y() < backgroundRect.y()){
459 this->setToolTip(i18n("Foreground color selector"));
460 }
461 else{
462 this->setToolTip(i18n("Set foreground and background colors to black and white"));
463 }
464 }
465 else {
466 if (this->mapFromGlobal(helpEvent->globalPos()).y() < backgroundRect.y() ) {
467 this->setToolTip(i18n("Swap foreground and background colors"));
468 }
469 else{
470 this->setToolTip(i18n("Background color selector"));
471 }
472 }
473 }
474 return QWidget::event(event);
475
476}
477
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()
setColorSpace set ColorSpace so we can lock the selector. Right now this'll be changed per view-chang...
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)