1// Copyright (C) 2016 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR LGPL-3.0-only OR GPL-2.0-only OR GPL-3.0-only
3
4#include "qcolordialog.h"
5
6#include "qapplication.h"
7#include "qdrawutil.h"
8#include "qevent.h"
9#include "qimage.h"
10#if QT_CONFIG(draganddrop)
11#include <qdrag.h>
12#endif
13#include "qlabel.h"
14#include "qlayout.h"
15#include "qlineedit.h"
16#if QT_CONFIG(menu)
17#include "qmenu.h"
18#endif
19#include "qpainter.h"
20#include "qpixmap.h"
21#include "qpushbutton.h"
22#if QT_CONFIG(regularexpression)
23#include <qregularexpression.h>
24#endif
25#if QT_CONFIG(settings)
26#include "qsettings.h"
27#endif
28#include "qsharedpointer.h"
29#include "qstyle.h"
30#include "qstyleoption.h"
31#include "qvalidator.h"
32#include "qmimedata.h"
33#include "qspinbox.h"
34#include "qdialogbuttonbox.h"
35#include "qscreen.h"
36#include "qcursor.h"
37#include "qtimer.h"
38#include "qwindow.h"
39
40#include "private/qdialog_p.h"
41
42#include <qpa/qplatformintegration.h>
43#include <qpa/qplatformservices.h>
44#include <private/qguiapplication_p.h>
45
46#include <QtCore/qpointer.h>
47
48#include <algorithm>
49
50QT_BEGIN_NAMESPACE
51
52using namespace Qt::StringLiterals;
53
54namespace QtPrivate {
55class QColorLuminancePicker;
56class QColorPicker;
57class QColorShower;
58class QWellArray;
59class QColorWell;
60class QColorPickingEventFilter;
61} // namespace QtPrivate
62
63using QColorLuminancePicker = QtPrivate::QColorLuminancePicker;
64using QColorPicker = QtPrivate::QColorPicker;
65using QColorShower = QtPrivate::QColorShower;
66using QWellArray = QtPrivate::QWellArray;
67using QColorWell = QtPrivate::QColorWell;
68using QColorPickingEventFilter = QtPrivate::QColorPickingEventFilter;
69
70class QColorDialogPrivate : public QDialogPrivate
71{
72 Q_DECLARE_PUBLIC(QColorDialog)
73
74public:
75 enum SetColorMode {
76 ShowColor = 0x1,
77 SelectColor = 0x2,
78 SetColorAll = ShowColor | SelectColor
79 };
80
81 QColorDialogPrivate() : options(QColorDialogOptions::create())
82#ifdef Q_OS_WIN32
83 , updateTimer(0)
84#endif
85 {}
86
87 QPlatformColorDialogHelper *platformColorDialogHelper() const
88 { return static_cast<QPlatformColorDialogHelper *>(platformHelper()); }
89
90 void init(const QColor &initial);
91 void initWidgets();
92 QRgb currentColor() const;
93 QColor currentQColor() const;
94 void setCurrentColor(const QColor &color, SetColorMode setColorMode = SetColorAll);
95 void setCurrentRgbColor(QRgb rgb);
96 void setCurrentQColor(const QColor &color);
97 bool selectColor(const QColor &color);
98 QColor grabScreenColor(const QPoint &p);
99
100 int currentAlpha() const;
101 void setCurrentAlpha(int a);
102 void showAlpha(bool b);
103 bool isAlphaVisible() const;
104 void retranslateStrings();
105 bool supportsColorPicking() const;
106
107 void addCustom();
108 void _q_setCustom(int index, QRgb color);
109
110 void newHsv(int h, int s, int v);
111 void newColorTypedIn(QRgb rgb);
112 void nextCustom(int, int);
113 void newCustom(int, int);
114 void newStandard(int, int);
115 void pickScreenColor();
116 void updateColorPicking();
117 void updateColorLabelText(const QPoint &);
118 void updateColorPicking(const QPoint &pos);
119 void releaseColorPicking();
120 bool handleColorPickingMouseMove(QMouseEvent *e);
121 bool handleColorPickingMouseButtonRelease(QMouseEvent *e);
122 bool handleColorPickingKeyPress(QKeyEvent *e);
123
124 bool canBeNativeDialog() const override;
125 void setVisible(bool visible) override;
126
127 QWellArray *custom;
128 QWellArray *standard;
129
130 QDialogButtonBox *buttons;
131 QVBoxLayout *leftLay;
132 QColorPicker *cp;
133 QColorLuminancePicker *lp;
134 QColorShower *cs;
135 QLabel *lblBasicColors;
136 QLabel *lblCustomColors;
137 QLabel *lblScreenColorInfo;
138 QPushButton *ok;
139 QPushButton *cancel;
140 QPushButton *addCusBt;
141 QPushButton *eyeDropperButton = nullptr;
142 QColor selectedQColor;
143 int nextCust;
144 bool smallDisplay;
145 bool screenColorPicking;
146 QColorPickingEventFilter *colorPickingEventFilter;
147 QRgb beforeScreenColorPicking;
148 QSharedPointer<QColorDialogOptions> options;
149
150 QPointer<QObject> receiverToDisconnectOnClose;
151 QByteArray memberToDisconnectOnClose;
152#ifdef Q_OS_WIN32
153 QTimer *updateTimer;
154 QWindow dummyTransparentWindow;
155#endif
156
157private:
158 virtual void initHelper(QPlatformDialogHelper *h) override;
159 virtual void helperPrepareShow(QPlatformDialogHelper *h) override;
160};
161
162//////////// QWellArray BEGIN
163
164namespace QtPrivate {
165
166class QWellArray : public QWidget
167{
168 Q_OBJECT
169 Q_PROPERTY(int selectedColumn READ selectedColumn)
170 Q_PROPERTY(int selectedRow READ selectedRow)
171
172public:
173 QWellArray(int rows, int cols, QWidget* parent=nullptr);
174 ~QWellArray() {}
175 QString cellContent(int row, int col) const;
176
177 int selectedColumn() const { return selCol; }
178 int selectedRow() const { return selRow; }
179
180 virtual void setCurrent(int row, int col);
181 virtual void setSelected(int row, int col);
182
183 QSize sizeHint() const override;
184
185 inline int cellWidth() const
186 { return cellw; }
187
188 inline int cellHeight() const
189 { return cellh; }
190
191 inline int rowAt(int y) const
192 { return y / cellh; }
193
194 inline int columnAt(int x) const
195 { if (isRightToLeft()) return ncols - (x / cellw) - 1; return x / cellw; }
196
197 inline int rowY(int row) const
198 { return cellh * row; }
199
200 inline int columnX(int column) const
201 { if (isRightToLeft()) return cellw * (ncols - column - 1); return cellw * column; }
202
203 inline int numRows() const
204 { return nrows; }
205
206 inline int numCols() const
207 {return ncols; }
208
209 inline QRect cellRect() const
210 { return QRect(0, 0, cellw, cellh); }
211
212 inline QSize gridSize() const
213 { return QSize(ncols * cellw, nrows * cellh); }
214
215 QRect cellGeometry(int row, int column)
216 {
217 QRect r;
218 if (row >= 0 && row < nrows && column >= 0 && column < ncols)
219 r.setRect(ax: columnX(column), ay: rowY(row), aw: cellw, ah: cellh);
220 return r;
221 }
222
223 inline void updateCell(int row, int column) { update(cellGeometry(row, column)); }
224
225signals:
226 void selected(int row, int col);
227 void currentChanged(int row, int col);
228 void colorChanged(int index, QRgb color);
229
230protected:
231 virtual void paintCell(QPainter *, int row, int col, const QRect&);
232 virtual void paintCellContents(QPainter *, int row, int col, const QRect&);
233
234 void mousePressEvent(QMouseEvent*) override;
235 void mouseReleaseEvent(QMouseEvent*) override;
236 void keyPressEvent(QKeyEvent*) override;
237 void focusInEvent(QFocusEvent*) override;
238 void focusOutEvent(QFocusEvent*) override;
239 void paintEvent(QPaintEvent *) override;
240
241private:
242 Q_DISABLE_COPY(QWellArray)
243
244 int nrows;
245 int ncols;
246 int cellw;
247 int cellh;
248 int curRow;
249 int curCol;
250 int selRow;
251 int selCol;
252};
253
254void QWellArray::paintEvent(QPaintEvent *e)
255{
256 QRect r = e->rect();
257 int cx = r.x();
258 int cy = r.y();
259 int ch = r.height();
260 int cw = r.width();
261 int colfirst = columnAt(x: cx);
262 int collast = columnAt(x: cx + cw);
263 int rowfirst = rowAt(y: cy);
264 int rowlast = rowAt(y: cy + ch);
265
266 if (isRightToLeft()) {
267 int t = colfirst;
268 colfirst = collast;
269 collast = t;
270 }
271
272 QPainter painter(this);
273 QPainter *p = &painter;
274 QRect rect(0, 0, cellWidth(), cellHeight());
275
276
277 if (collast < 0 || collast >= ncols)
278 collast = ncols-1;
279 if (rowlast < 0 || rowlast >= nrows)
280 rowlast = nrows-1;
281
282 // Go through the rows
283 for (int r = rowfirst; r <= rowlast; ++r) {
284 // get row position and height
285 int rowp = rowY(row: r);
286
287 // Go through the columns in the row r
288 // if we know from where to where, go through [colfirst, collast],
289 // else go through all of them
290 for (int c = colfirst; c <= collast; ++c) {
291 // get position and width of column c
292 int colp = columnX(column: c);
293 // Translate painter and draw the cell
294 rect.translate(dx: colp, dy: rowp);
295 paintCell(p, row: r, col: c, rect);
296 rect.translate(dx: -colp, dy: -rowp);
297 }
298 }
299}
300
301QWellArray::QWellArray(int rows, int cols, QWidget *parent)
302 : QWidget(parent)
303 ,nrows(rows), ncols(cols)
304{
305 setFocusPolicy(Qt::StrongFocus);
306 cellw = 28;
307 cellh = 24;
308 curCol = 0;
309 curRow = 0;
310 selCol = -1;
311 selRow = -1;
312}
313
314QSize QWellArray::sizeHint() const
315{
316 ensurePolished();
317 return gridSize().boundedTo(otherSize: QSize(640, 480));
318}
319
320
321void QWellArray::paintCell(QPainter* p, int row, int col, const QRect &rect)
322{
323 int b = 3; //margin
324
325 const QPalette & g = palette();
326 QStyleOptionFrame opt;
327 opt.initFrom(w: this);
328 int dfw = style()->pixelMetric(metric: QStyle::PM_DefaultFrameWidth, option: &opt, widget: this);
329 opt.lineWidth = dfw;
330 opt.midLineWidth = 1;
331 opt.rect = rect.adjusted(xp1: b, yp1: b, xp2: -b, yp2: -b);
332 opt.palette = g;
333 opt.state = QStyle::State_Enabled | QStyle::State_Sunken;
334 style()->drawPrimitive(pe: QStyle::PE_Frame, opt: &opt, p, w: this);
335 b += dfw;
336
337 if ((row == curRow) && (col == curCol)) {
338 if (hasFocus()) {
339 QStyleOptionFocusRect opt;
340 opt.palette = g;
341 opt.rect = rect;
342 opt.state = QStyle::State_None | QStyle::State_KeyboardFocusChange;
343 style()->drawPrimitive(pe: QStyle::PE_FrameFocusRect, opt: &opt, p, w: this);
344 }
345 }
346 paintCellContents(p, row, col, opt.rect.adjusted(xp1: dfw, yp1: dfw, xp2: -dfw, yp2: -dfw));
347}
348
349/*
350 Reimplement this function to change the contents of the well array.
351 */
352void QWellArray::paintCellContents(QPainter *p, int row, int col, const QRect &r)
353{
354 Q_UNUSED(row);
355 Q_UNUSED(col);
356 p->fillRect(r, c: Qt::white);
357 p->setPen(Qt::black);
358 p->drawLine(p1: r.topLeft(), p2: r.bottomRight());
359 p->drawLine(p1: r.topRight(), p2: r.bottomLeft());
360}
361
362void QWellArray::mousePressEvent(QMouseEvent *e)
363{
364 // The current cell marker is set to the cell the mouse is pressed in
365 QPoint pos = e->position().toPoint();
366 setCurrent(row: rowAt(y: pos.y()), col: columnAt(x: pos.x()));
367}
368
369void QWellArray::mouseReleaseEvent(QMouseEvent * /* event */)
370{
371 // The current cell marker is set to the cell the mouse is clicked in
372 setSelected(row: curRow, col: curCol);
373}
374
375
376/*
377 Sets the cell currently having the focus. This is not necessarily
378 the same as the currently selected cell.
379*/
380
381void QWellArray::setCurrent(int row, int col)
382{
383 if ((curRow == row) && (curCol == col))
384 return;
385
386 if (row < 0 || col < 0)
387 row = col = -1;
388
389 int oldRow = curRow;
390 int oldCol = curCol;
391
392 curRow = row;
393 curCol = col;
394
395 updateCell(row: oldRow, column: oldCol);
396 updateCell(row: curRow, column: curCol);
397
398 emit currentChanged(row: curRow, col: curCol);
399}
400
401/*
402 Sets the currently selected cell to \a row, \a column. If \a row or
403 \a column are less than zero, the current cell is unselected.
404
405 Does not set the position of the focus indicator.
406*/
407void QWellArray::setSelected(int row, int col)
408{
409 int oldRow = selRow;
410 int oldCol = selCol;
411
412 if (row < 0 || col < 0)
413 row = col = -1;
414
415 selCol = col;
416 selRow = row;
417
418 updateCell(row: oldRow, column: oldCol);
419 updateCell(row: selRow, column: selCol);
420 if (row >= 0)
421 emit selected(row, col);
422
423#if QT_CONFIG(menu)
424 if (isVisible() && qobject_cast<QMenu*>(object: parentWidget()))
425 parentWidget()->close();
426#endif
427}
428
429void QWellArray::focusInEvent(QFocusEvent*)
430{
431 updateCell(row: curRow, column: curCol);
432 emit currentChanged(row: curRow, col: curCol);
433}
434
435
436void QWellArray::focusOutEvent(QFocusEvent*)
437{
438 updateCell(row: curRow, column: curCol);
439}
440
441void QWellArray::keyPressEvent(QKeyEvent* e)
442{
443 switch(e->key()) { // Look at the key code
444 case Qt::Key_Left: // If 'left arrow'-key,
445 if (curCol > 0) // and cr't not in leftmost col
446 setCurrent(row: curRow, col: curCol - 1); // set cr't to next left column
447 break;
448 case Qt::Key_Right: // Correspondingly...
449 if (curCol < numCols()-1)
450 setCurrent(row: curRow, col: curCol + 1);
451 break;
452 case Qt::Key_Up:
453 if (curRow > 0)
454 setCurrent(row: curRow - 1, col: curCol);
455 break;
456 case Qt::Key_Down:
457 if (curRow < numRows()-1)
458 setCurrent(row: curRow + 1, col: curCol);
459 break;
460#if 0
461 // bad idea that shouldn't have been implemented; very counterintuitive
462 case Qt::Key_Return:
463 case Qt::Key_Enter:
464 /*
465 ignore the key, so that the dialog get it, but still select
466 the current row/col
467 */
468 e->ignore();
469 // fallthrough intended
470#endif
471 case Qt::Key_Space:
472 setSelected(row: curRow, col: curCol);
473 break;
474 default: // If not an interesting key,
475 e->ignore(); // we don't accept the event
476 return;
477 }
478
479} // namespace QtPrivate
480
481//////////// QWellArray END
482
483// Event filter to be installed on the dialog while in color-picking mode.
484class QColorPickingEventFilter : public QObject {
485public:
486 explicit QColorPickingEventFilter(QColorDialogPrivate *dp, QObject *parent) : QObject(parent), m_dp(dp) {}
487
488 bool eventFilter(QObject *, QEvent *event) override
489 {
490 switch (event->type()) {
491 case QEvent::MouseMove:
492 return m_dp->handleColorPickingMouseMove(e: static_cast<QMouseEvent *>(event));
493 case QEvent::MouseButtonRelease:
494 return m_dp->handleColorPickingMouseButtonRelease(e: static_cast<QMouseEvent *>(event));
495 case QEvent::KeyPress:
496 return m_dp->handleColorPickingKeyPress(e: static_cast<QKeyEvent *>(event));
497 default:
498 break;
499 }
500 return false;
501 }
502
503 void applicationStateChanged(Qt::ApplicationState state)
504 {
505 if (state != Qt::ApplicationActive)
506 m_dp->releaseColorPicking();
507 }
508
509private:
510 QColorDialogPrivate *m_dp;
511};
512
513} // unnamed namespace
514
515/*!
516 Returns the number of custom colors supported by QColorDialog. All
517 color dialogs share the same custom colors.
518*/
519int QColorDialog::customCount()
520{
521 return QColorDialogOptions::customColorCount();
522}
523
524/*!
525 Returns the custom color at the given \a index as a QColor value.
526*/
527QColor QColorDialog::customColor(int index)
528{
529 return QColor(QColorDialogOptions::customColor(index));
530}
531
532/*!
533 Sets the custom color at \a index to the QColor \a color value.
534
535 \note This function does not apply to the Native Color Dialog on the
536 \macos platform. If you still require this function, use the
537 QColorDialog::DontUseNativeDialog option.
538*/
539void QColorDialog::setCustomColor(int index, QColor color)
540{
541 QColorDialogOptions::setCustomColor(index, color: color.rgba());
542}
543
544/*!
545 \since 5.0
546
547 Returns the standard color at the given \a index as a QColor value.
548*/
549QColor QColorDialog::standardColor(int index)
550{
551 return QColor(QColorDialogOptions::standardColor(index));
552}
553
554/*!
555 Sets the standard color at \a index to the QColor \a color value.
556
557 \note This function does not apply to the Native Color Dialog on the
558 \macos platform. If you still require this function, use the
559 QColorDialog::DontUseNativeDialog option.
560*/
561void QColorDialog::setStandardColor(int index, QColor color)
562{
563 QColorDialogOptions::setStandardColor(index, color: color.rgba());
564}
565
566static inline void rgb2hsv(QRgb rgb, int &h, int &s, int &v)
567{
568 QColor c;
569 c.setRgb(rgb);
570 c.getHsv(h: &h, s: &s, v: &v);
571}
572
573namespace QtPrivate {
574
575class QColorWell : public QWellArray
576{
577public:
578 QColorWell(QWidget *parent, int r, int c, const QRgb *vals)
579 :QWellArray(r, c, parent), values(vals), mousePressed(false), oldCurrent(-1, -1)
580 { setSizePolicy(QSizePolicy(QSizePolicy::Minimum, QSizePolicy::Minimum)); }
581
582protected:
583 void paintCellContents(QPainter *, int row, int col, const QRect&) override;
584 void mousePressEvent(QMouseEvent *e) override;
585 void mouseMoveEvent(QMouseEvent *e) override;
586 void mouseReleaseEvent(QMouseEvent *e) override;
587#if QT_CONFIG(draganddrop)
588 void dragEnterEvent(QDragEnterEvent *e) override;
589 void dragLeaveEvent(QDragLeaveEvent *e) override;
590 void dragMoveEvent(QDragMoveEvent *e) override;
591 void dropEvent(QDropEvent *e) override;
592#endif
593
594private:
595 const QRgb *values;
596 bool mousePressed;
597 QPoint pressPos;
598 QPoint oldCurrent;
599
600};
601
602void QColorWell::paintCellContents(QPainter *p, int row, int col, const QRect &r)
603{
604 int i = row + col*numRows();
605 p->fillRect(r, color: QColor(values[i]));
606}
607
608void QColorWell::mousePressEvent(QMouseEvent *e)
609{
610 oldCurrent = QPoint(selectedRow(), selectedColumn());
611 QWellArray::mousePressEvent(e);
612 mousePressed = true;
613 pressPos = e->position().toPoint();
614}
615
616void QColorWell::mouseMoveEvent(QMouseEvent *e)
617{
618 QWellArray::mouseMoveEvent(event: e);
619#if QT_CONFIG(draganddrop)
620 if (!mousePressed)
621 return;
622 if ((pressPos - e->position().toPoint()).manhattanLength() > QApplication::startDragDistance()) {
623 setCurrent(row: oldCurrent.x(), col: oldCurrent.y());
624 int i = rowAt(y: pressPos.y()) + columnAt(x: pressPos.x()) * numRows();
625 QColor col(values[i]);
626 QMimeData *mime = new QMimeData;
627 mime->setColorData(col);
628 QPixmap pix(cellWidth(), cellHeight());
629 pix.fill(fillColor: col);
630 QPainter p(&pix);
631 p.drawRect(x: 0, y: 0, w: pix.width() - 1, h: pix.height() - 1);
632 p.end();
633 QDrag *drg = new QDrag(this);
634 drg->setMimeData(mime);
635 drg->setPixmap(pix);
636 mousePressed = false;
637 drg->exec(supportedActions: Qt::CopyAction);
638 }
639#endif
640}
641
642#if QT_CONFIG(draganddrop)
643void QColorWell::dragEnterEvent(QDragEnterEvent *e)
644{
645 if (qvariant_cast<QColor>(v: e->mimeData()->colorData()).isValid())
646 e->accept();
647 else
648 e->ignore();
649}
650
651void QColorWell::dragLeaveEvent(QDragLeaveEvent *)
652{
653 if (hasFocus())
654 parentWidget()->setFocus();
655}
656
657void QColorWell::dragMoveEvent(QDragMoveEvent *e)
658{
659 if (qvariant_cast<QColor>(v: e->mimeData()->colorData()).isValid()) {
660 setCurrent(row: rowAt(y: e->position().toPoint().y()), col: columnAt(x: e->position().toPoint().x()));
661 e->accept();
662 } else {
663 e->ignore();
664 }
665}
666
667void QColorWell::dropEvent(QDropEvent *e)
668{
669 QColor col = qvariant_cast<QColor>(v: e->mimeData()->colorData());
670 if (col.isValid()) {
671 int i = rowAt(y: e->position().toPoint().y()) + columnAt(x: e->position().toPoint().x()) * numRows();
672 emit colorChanged(index: i, color: col.rgb());
673 e->accept();
674 } else {
675 e->ignore();
676 }
677}
678
679#endif // QT_CONFIG(draganddrop)
680
681void QColorWell::mouseReleaseEvent(QMouseEvent *e)
682{
683 if (!mousePressed)
684 return;
685 QWellArray::mouseReleaseEvent(e);
686 mousePressed = false;
687}
688
689class QColorPicker : public QFrame
690{
691 Q_OBJECT
692public:
693 QColorPicker(QWidget* parent);
694 ~QColorPicker();
695
696 void setCrossVisible(bool visible);
697public slots:
698 void setCol(int h, int s);
699
700signals:
701 void newCol(int h, int s);
702
703protected:
704 QSize sizeHint() const override;
705 void paintEvent(QPaintEvent*) override;
706 void mouseMoveEvent(QMouseEvent *) override;
707 void mousePressEvent(QMouseEvent *) override;
708 void resizeEvent(QResizeEvent *) override;
709
710private:
711 int hue;
712 int sat;
713
714 QPoint colPt();
715 int huePt(const QPoint &pt);
716 int satPt(const QPoint &pt);
717 void setCol(const QPoint &pt);
718
719 QPixmap pix;
720 bool crossVisible;
721};
722
723} // namespace QtPrivate
724
725static int pWidth = 220;
726static int pHeight = 200;
727
728namespace QtPrivate {
729
730class QColorLuminancePicker : public QWidget
731{
732 Q_OBJECT
733public:
734 QColorLuminancePicker(QWidget* parent=nullptr);
735 ~QColorLuminancePicker();
736
737public slots:
738 void setCol(int h, int s, int v);
739 void setCol(int h, int s);
740
741signals:
742 void newHsv(int h, int s, int v);
743
744protected:
745 void paintEvent(QPaintEvent*) override;
746 void mouseMoveEvent(QMouseEvent *) override;
747 void mousePressEvent(QMouseEvent *) override;
748
749private:
750 enum { foff = 3, coff = 4 }; //frame and contents offset
751 int val;
752 int hue;
753 int sat;
754
755 int y2val(int y);
756 int val2y(int val);
757 void setVal(int v);
758
759 QPixmap *pix;
760};
761
762
763int QColorLuminancePicker::y2val(int y)
764{
765 int d = height() - 2*coff - 1;
766 return 255 - (y - coff)*255/d;
767}
768
769int QColorLuminancePicker::val2y(int v)
770{
771 int d = height() - 2*coff - 1;
772 return coff + (255-v)*d/255;
773}
774
775QColorLuminancePicker::QColorLuminancePicker(QWidget* parent)
776 :QWidget(parent)
777{
778 hue = 100; val = 100; sat = 100;
779 pix = nullptr;
780 // setAttribute(WA_NoErase, true);
781}
782
783QColorLuminancePicker::~QColorLuminancePicker()
784{
785 delete pix;
786}
787
788void QColorLuminancePicker::mouseMoveEvent(QMouseEvent *m)
789{
790 if (m->buttons() == Qt::NoButton) {
791 m->ignore();
792 return;
793 }
794 setVal(y2val(y: m->position().toPoint().y()));
795}
796void QColorLuminancePicker::mousePressEvent(QMouseEvent *m)
797{
798 setVal(y2val(y: m->position().toPoint().y()));
799}
800
801void QColorLuminancePicker::setVal(int v)
802{
803 if (val == v)
804 return;
805 val = qMax(a: 0, b: qMin(a: v,b: 255));
806 delete pix; pix=nullptr;
807 repaint();
808 emit newHsv(h: hue, s: sat, v: val);
809}
810
811//receives from a hue,sat chooser and relays.
812void QColorLuminancePicker::setCol(int h, int s)
813{
814 setCol(h, s, v: val);
815 emit newHsv(h, s, v: val);
816}
817
818void QColorLuminancePicker::paintEvent(QPaintEvent *)
819{
820 int w = width() - 5;
821
822 QRect r(0, foff, w, height() - 2*foff);
823 int wi = r.width() - 2;
824 int hi = r.height() - 2;
825 if (!pix || pix->height() != hi || pix->width() != wi) {
826 delete pix;
827 QImage img(wi, hi, QImage::Format_RGB32);
828 int y;
829 uint *pixel = (uint *) img.scanLine(0);
830 for (y = 0; y < hi; y++) {
831 uint *end = pixel + wi;
832 std::fill(first: pixel, last: end, value: QColor::fromHsv(h: hue, s: sat, v: y2val(y: y + coff)).rgb());
833 pixel = end;
834 }
835 pix = new QPixmap(QPixmap::fromImage(image: img));
836 }
837 QPainter p(this);
838 p.drawPixmap(x: 1, y: coff, pm: *pix);
839 const QPalette &g = palette();
840 qDrawShadePanel(p: &p, r, pal: g, sunken: true);
841 p.setPen(g.windowText().color());
842 p.setBrush(g.windowText());
843 p.eraseRect(x: w, y: 0, w: 5, h: height());
844 const int y = val2y(v: val);
845 const std::array<QPoint, 3> points = {QPoint(w, y), QPoint(w + 5, y + 5), QPoint(w + 5, y - 5)};
846 p.drawPolygon(points: points.data(), pointCount: static_cast<int>(points.size()));
847}
848
849void QColorLuminancePicker::setCol(int h, int s , int v)
850{
851 val = v;
852 hue = h;
853 sat = s;
854 delete pix; pix=nullptr;
855 repaint();
856}
857
858QPoint QColorPicker::colPt()
859{
860 QRect r = contentsRect();
861 return QPoint((360 - hue) * (r.width() - 1) / 360, (255 - sat) * (r.height() - 1) / 255);
862}
863
864int QColorPicker::huePt(const QPoint &pt)
865{
866 QRect r = contentsRect();
867 return 360 - pt.x() * 360 / (r.width() - 1);
868}
869
870int QColorPicker::satPt(const QPoint &pt)
871{
872 QRect r = contentsRect();
873 return 255 - pt.y() * 255 / (r.height() - 1);
874}
875
876void QColorPicker::setCol(const QPoint &pt)
877{
878 setCol(h: huePt(pt), s: satPt(pt));
879}
880
881QColorPicker::QColorPicker(QWidget* parent)
882 : QFrame(parent)
883 , crossVisible(true)
884{
885 hue = 0; sat = 0;
886 setCol(h: 150, s: 255);
887
888 setAttribute(Qt::WA_NoSystemBackground);
889 setSizePolicy(QSizePolicy(QSizePolicy::Fixed, QSizePolicy::Fixed) );
890}
891
892QColorPicker::~QColorPicker()
893{
894}
895
896void QColorPicker::setCrossVisible(bool visible)
897{
898 if (crossVisible != visible) {
899 crossVisible = visible;
900 update();
901 }
902}
903
904QSize QColorPicker::sizeHint() const
905{
906 return QSize(pWidth + 2*frameWidth(), pHeight + 2*frameWidth());
907}
908
909void QColorPicker::setCol(int h, int s)
910{
911 int nhue = qMin(a: qMax(a: 0,b: h), b: 359);
912 int nsat = qMin(a: qMax(a: 0,b: s), b: 255);
913 if (nhue == hue && nsat == sat)
914 return;
915
916 QRect r(colPt(), QSize(20,20));
917 hue = nhue; sat = nsat;
918 r = r.united(r: QRect(colPt(), QSize(20,20)));
919 r.translate(dx: contentsRect().x()-9, dy: contentsRect().y()-9);
920 // update(r);
921 repaint(r);
922}
923
924void QColorPicker::mouseMoveEvent(QMouseEvent *m)
925{
926 QPoint p = m->position().toPoint() - contentsRect().topLeft();
927 if (m->buttons() == Qt::NoButton) {
928 m->ignore();
929 return;
930 }
931 setCol(p);
932 emit newCol(h: hue, s: sat);
933}
934
935void QColorPicker::mousePressEvent(QMouseEvent *m)
936{
937 QPoint p = m->position().toPoint() - contentsRect().topLeft();
938 setCol(p);
939 emit newCol(h: hue, s: sat);
940}
941
942void QColorPicker::paintEvent(QPaintEvent* )
943{
944 QPainter p(this);
945 drawFrame(&p);
946 QRect r = contentsRect();
947
948 p.drawPixmap(p: r.topLeft(), pm: pix);
949
950 if (crossVisible) {
951 QPoint pt = colPt() + r.topLeft();
952 p.setPen(Qt::black);
953 p.fillRect(x: pt.x()-9, y: pt.y(), w: 20, h: 2, c: Qt::black);
954 p.fillRect(x: pt.x(), y: pt.y()-9, w: 2, h: 20, c: Qt::black);
955 }
956}
957
958void QColorPicker::resizeEvent(QResizeEvent *ev)
959{
960 QFrame::resizeEvent(event: ev);
961
962 int w = width() - frameWidth() * 2;
963 int h = height() - frameWidth() * 2;
964 QImage img(w, h, QImage::Format_RGB32);
965 int x, y;
966 uint *pixel = (uint *) img.scanLine(0);
967 for (y = 0; y < h; y++) {
968 const uint *end = pixel + w;
969 x = 0;
970 while (pixel < end) {
971 QPoint p(x, y);
972 QColor c;
973 c.setHsv(h: huePt(pt: p), s: satPt(pt: p), v: 200);
974 *pixel = c.rgb();
975 ++pixel;
976 ++x;
977 }
978 }
979 pix = QPixmap::fromImage(image: img);
980}
981
982
983class QColSpinBox : public QSpinBox
984{
985public:
986 QColSpinBox(QWidget *parent)
987 : QSpinBox(parent) { setRange(min: 0, max: 255); }
988 void setValue(int i) {
989 const QSignalBlocker blocker(this);
990 QSpinBox::setValue(i);
991 }
992};
993
994class QColorShowLabel;
995
996class QColorShower : public QWidget
997{
998 Q_OBJECT
999public:
1000 QColorShower(QColorDialog *parent);
1001
1002 //things that don't emit signals
1003 void setHsv(int h, int s, int v);
1004
1005 int currentAlpha() const
1006 { return (colorDialog->options() & QColorDialog::ShowAlphaChannel) ? alphaEd->value() : 255; }
1007 void setCurrentAlpha(int a) { alphaEd->setValue(a); rgbEd(); }
1008 void showAlpha(bool b);
1009 bool isAlphaVisible() const;
1010
1011 QRgb currentColor() const { return curCol; }
1012 QColor currentQColor() const { return curQColor; }
1013 void retranslateStrings();
1014 void updateQColor();
1015
1016public slots:
1017 void setRgb(QRgb rgb);
1018
1019signals:
1020 void newCol(QRgb rgb);
1021 void currentColorChanged(const QColor &color);
1022
1023private slots:
1024 void rgbEd();
1025 void hsvEd();
1026 void htmlEd();
1027
1028private:
1029 void showCurrentColor();
1030 int hue, sat, val;
1031 QRgb curCol;
1032 QColor curQColor;
1033 QLabel *lblHue;
1034 QLabel *lblSat;
1035 QLabel *lblVal;
1036 QLabel *lblRed;
1037 QLabel *lblGreen;
1038 QLabel *lblBlue;
1039 QLabel *lblHtml;
1040 QColSpinBox *hEd;
1041 QColSpinBox *sEd;
1042 QColSpinBox *vEd;
1043 QColSpinBox *rEd;
1044 QColSpinBox *gEd;
1045 QColSpinBox *bEd;
1046 QColSpinBox *alphaEd;
1047 QLabel *alphaLab;
1048 QLineEdit *htEd;
1049 QColorShowLabel *lab;
1050 bool rgbOriginal;
1051 QColorDialog *colorDialog;
1052 QGridLayout *gl;
1053
1054 friend class QT_PREPEND_NAMESPACE(QColorDialog);
1055 friend class QT_PREPEND_NAMESPACE(QColorDialogPrivate);
1056};
1057
1058class QColorShowLabel : public QFrame
1059{
1060 Q_OBJECT
1061
1062public:
1063 QColorShowLabel(QWidget *parent) : QFrame(parent) {
1064 setFrameStyle(QFrame::Panel|QFrame::Sunken);
1065 setAcceptDrops(true);
1066 mousePressed = false;
1067 }
1068 void setColor(QColor c) { col = c; }
1069
1070signals:
1071 void colorDropped(QRgb);
1072
1073protected:
1074 void paintEvent(QPaintEvent *) override;
1075 void mousePressEvent(QMouseEvent *e) override;
1076 void mouseMoveEvent(QMouseEvent *e) override;
1077 void mouseReleaseEvent(QMouseEvent *e) override;
1078#if QT_CONFIG(draganddrop)
1079 void dragEnterEvent(QDragEnterEvent *e) override;
1080 void dragLeaveEvent(QDragLeaveEvent *e) override;
1081 void dropEvent(QDropEvent *e) override;
1082#endif
1083
1084private:
1085 QColor col;
1086 bool mousePressed;
1087 QPoint pressPos;
1088};
1089
1090void QColorShowLabel::paintEvent(QPaintEvent *e)
1091{
1092 QPainter p(this);
1093 drawFrame(&p);
1094 p.fillRect(contentsRect()&e->rect(), color: col);
1095}
1096
1097void QColorShower::showAlpha(bool b)
1098{
1099 alphaLab->setVisible(b);
1100 alphaEd->setVisible(b);
1101}
1102
1103inline bool QColorShower::isAlphaVisible() const
1104{
1105 return alphaLab->isVisible();
1106}
1107
1108void QColorShowLabel::mousePressEvent(QMouseEvent *e)
1109{
1110 mousePressed = true;
1111 pressPos = e->position().toPoint();
1112}
1113
1114void QColorShowLabel::mouseMoveEvent(QMouseEvent *e)
1115{
1116#if !QT_CONFIG(draganddrop)
1117 Q_UNUSED(e);
1118#else
1119 if (!mousePressed)
1120 return;
1121 if ((pressPos - e->position().toPoint()).manhattanLength() > QApplication::startDragDistance()) {
1122 QMimeData *mime = new QMimeData;
1123 mime->setColorData(col);
1124 QPixmap pix(30, 20);
1125 pix.fill(fillColor: col);
1126 QPainter p(&pix);
1127 p.drawRect(x: 0, y: 0, w: pix.width() - 1, h: pix.height() - 1);
1128 p.end();
1129 QDrag *drg = new QDrag(this);
1130 drg->setMimeData(mime);
1131 drg->setPixmap(pix);
1132 mousePressed = false;
1133 drg->exec(supportedActions: Qt::CopyAction);
1134 }
1135#endif
1136}
1137
1138#if QT_CONFIG(draganddrop)
1139void QColorShowLabel::dragEnterEvent(QDragEnterEvent *e)
1140{
1141 if (qvariant_cast<QColor>(v: e->mimeData()->colorData()).isValid())
1142 e->accept();
1143 else
1144 e->ignore();
1145}
1146
1147void QColorShowLabel::dragLeaveEvent(QDragLeaveEvent *)
1148{
1149}
1150
1151void QColorShowLabel::dropEvent(QDropEvent *e)
1152{
1153 QColor color = qvariant_cast<QColor>(v: e->mimeData()->colorData());
1154 if (color.isValid()) {
1155 col = color;
1156 repaint();
1157 emit colorDropped(col.rgb());
1158 e->accept();
1159 } else {
1160 e->ignore();
1161 }
1162}
1163#endif // QT_CONFIG(draganddrop)
1164
1165void QColorShowLabel::mouseReleaseEvent(QMouseEvent *)
1166{
1167 if (!mousePressed)
1168 return;
1169 mousePressed = false;
1170}
1171
1172QColorShower::QColorShower(QColorDialog *parent)
1173 : QWidget(parent)
1174{
1175 colorDialog = parent;
1176
1177 curCol = qRgb(r: 255, g: 255, b: 255);
1178 curQColor = Qt::white;
1179
1180 gl = new QGridLayout(this);
1181 const int s = gl->spacing();
1182 gl->setContentsMargins(left: s, top: s, right: s, bottom: s);
1183 lab = new QColorShowLabel(this);
1184
1185#ifdef QT_SMALL_COLORDIALOG
1186 lab->setMinimumHeight(60);
1187#endif
1188 lab->setMinimumWidth(60);
1189
1190// For QVGA screens only the comboboxes and color label are visible.
1191// For nHD screens only color and luminence pickers and color label are visible.
1192#if !defined(QT_SMALL_COLORDIALOG)
1193 gl->addWidget(lab, row: 0, column: 0, rowSpan: -1, columnSpan: 1);
1194#else
1195 gl->addWidget(lab, 0, 0, 1, -1);
1196#endif
1197 connect(sender: lab, signal: &QColorShowLabel::colorDropped, context: this, slot: &QColorShower::newCol);
1198 connect(sender: lab, signal: &QColorShowLabel::colorDropped, context: this, slot: &QColorShower::setRgb);
1199
1200 hEd = new QColSpinBox(this);
1201 hEd->setRange(min: 0, max: 359);
1202 lblHue = new QLabel(this);
1203#ifndef QT_NO_SHORTCUT
1204 lblHue->setBuddy(hEd);
1205#endif
1206 lblHue->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
1207#if !defined(QT_SMALL_COLORDIALOG)
1208 gl->addWidget(lblHue, row: 0, column: 1);
1209 gl->addWidget(hEd, row: 0, column: 2);
1210#else
1211 gl->addWidget(lblHue, 1, 0);
1212 gl->addWidget(hEd, 2, 0);
1213#endif
1214
1215 sEd = new QColSpinBox(this);
1216 lblSat = new QLabel(this);
1217#ifndef QT_NO_SHORTCUT
1218 lblSat->setBuddy(sEd);
1219#endif
1220 lblSat->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
1221#if !defined(QT_SMALL_COLORDIALOG)
1222 gl->addWidget(lblSat, row: 1, column: 1);
1223 gl->addWidget(sEd, row: 1, column: 2);
1224#else
1225 gl->addWidget(lblSat, 1, 1);
1226 gl->addWidget(sEd, 2, 1);
1227#endif
1228
1229 vEd = new QColSpinBox(this);
1230 lblVal = new QLabel(this);
1231#ifndef QT_NO_SHORTCUT
1232 lblVal->setBuddy(vEd);
1233#endif
1234 lblVal->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
1235#if !defined(QT_SMALL_COLORDIALOG)
1236 gl->addWidget(lblVal, row: 2, column: 1);
1237 gl->addWidget(vEd, row: 2, column: 2);
1238#else
1239 gl->addWidget(lblVal, 1, 2);
1240 gl->addWidget(vEd, 2, 2);
1241#endif
1242
1243 rEd = new QColSpinBox(this);
1244 lblRed = new QLabel(this);
1245#ifndef QT_NO_SHORTCUT
1246 lblRed->setBuddy(rEd);
1247#endif
1248 lblRed->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
1249#if !defined(QT_SMALL_COLORDIALOG)
1250 gl->addWidget(lblRed, row: 0, column: 3);
1251 gl->addWidget(rEd, row: 0, column: 4);
1252#else
1253 gl->addWidget(lblRed, 3, 0);
1254 gl->addWidget(rEd, 4, 0);
1255#endif
1256
1257 gEd = new QColSpinBox(this);
1258 lblGreen = new QLabel(this);
1259#ifndef QT_NO_SHORTCUT
1260 lblGreen->setBuddy(gEd);
1261#endif
1262 lblGreen->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
1263#if !defined(QT_SMALL_COLORDIALOG)
1264 gl->addWidget(lblGreen, row: 1, column: 3);
1265 gl->addWidget(gEd, row: 1, column: 4);
1266#else
1267 gl->addWidget(lblGreen, 3, 1);
1268 gl->addWidget(gEd, 4, 1);
1269#endif
1270
1271 bEd = new QColSpinBox(this);
1272 lblBlue = new QLabel(this);
1273#ifndef QT_NO_SHORTCUT
1274 lblBlue->setBuddy(bEd);
1275#endif
1276 lblBlue->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
1277#if !defined(QT_SMALL_COLORDIALOG)
1278 gl->addWidget(lblBlue, row: 2, column: 3);
1279 gl->addWidget(bEd, row: 2, column: 4);
1280#else
1281 gl->addWidget(lblBlue, 3, 2);
1282 gl->addWidget(bEd, 4, 2);
1283#endif
1284
1285 alphaEd = new QColSpinBox(this);
1286 alphaLab = new QLabel(this);
1287#ifndef QT_NO_SHORTCUT
1288 alphaLab->setBuddy(alphaEd);
1289#endif
1290 alphaLab->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
1291#if !defined(QT_SMALL_COLORDIALOG)
1292 gl->addWidget(alphaLab, row: 3, column: 1, rowSpan: 1, columnSpan: 3);
1293 gl->addWidget(alphaEd, row: 3, column: 4);
1294#else
1295 gl->addWidget(alphaLab, 1, 3, 3, 1);
1296 gl->addWidget(alphaEd, 4, 3);
1297#endif
1298 alphaEd->hide();
1299 alphaLab->hide();
1300 lblHtml = new QLabel(this);
1301 htEd = new QLineEdit(this);
1302 htEd->setObjectName("qt_colorname_lineedit");
1303#ifndef QT_NO_SHORTCUT
1304 lblHtml->setBuddy(htEd);
1305#endif
1306
1307#if QT_CONFIG(regularexpression)
1308 QRegularExpression regExp(QStringLiteral("#?([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})"));
1309 QRegularExpressionValidator *validator = new QRegularExpressionValidator(regExp, this);
1310 htEd->setValidator(validator);
1311#else
1312 htEd->setReadOnly(true);
1313#endif
1314 htEd->setSizePolicy(hor: QSizePolicy::Maximum, ver: QSizePolicy::Fixed);
1315
1316 lblHtml->setAlignment(Qt::AlignRight|Qt::AlignVCenter);
1317#if defined(QT_SMALL_COLORDIALOG)
1318 gl->addWidget(lblHtml, 5, 0);
1319 gl->addWidget(htEd, 5, 1, 1, /*colspan=*/ 2);
1320#else
1321 gl->addWidget(lblHtml, row: 5, column: 1);
1322 gl->addWidget(htEd, row: 5, column: 2, rowSpan: 1, /*colspan=*/ columnSpan: 3);
1323#endif
1324
1325 connect(sender: hEd, signal: &QSpinBox::valueChanged, context: this, slot: &QColorShower::hsvEd);
1326 connect(sender: sEd, signal: &QSpinBox::valueChanged, context: this, slot: &QColorShower::hsvEd);
1327 connect(sender: vEd, signal: &QSpinBox::valueChanged, context: this, slot: &QColorShower::hsvEd);
1328
1329 connect(sender: rEd, signal: &QSpinBox::valueChanged, context: this, slot: &QColorShower::rgbEd);
1330 connect(sender: gEd, signal: &QSpinBox::valueChanged, context: this, slot: &QColorShower::rgbEd);
1331 connect(sender: bEd, signal: &QSpinBox::valueChanged, context: this, slot: &QColorShower::rgbEd);
1332 connect(sender: alphaEd, signal: &QSpinBox::valueChanged, context: this, slot: &QColorShower::rgbEd);
1333 connect(sender: htEd, signal: &QLineEdit::textEdited, context: this, slot: &QColorShower::htmlEd);
1334
1335 retranslateStrings();
1336}
1337
1338} // namespace QtPrivate
1339
1340inline QRgb QColorDialogPrivate::currentColor() const { return cs->currentColor(); }
1341inline int QColorDialogPrivate::currentAlpha() const { return cs->currentAlpha(); }
1342inline void QColorDialogPrivate::setCurrentAlpha(int a) { cs->setCurrentAlpha(a); }
1343inline void QColorDialogPrivate::showAlpha(bool b) { cs->showAlpha(b); }
1344inline bool QColorDialogPrivate::isAlphaVisible() const { return cs->isAlphaVisible(); }
1345
1346QColor QColorDialogPrivate::currentQColor() const
1347{
1348 if (nativeDialogInUse)
1349 return platformColorDialogHelper()->currentColor();
1350 return cs->currentQColor();
1351}
1352
1353void QColorShower::showCurrentColor()
1354{
1355 lab->setColor(currentColor());
1356 lab->repaint();
1357}
1358
1359void QColorShower::rgbEd()
1360{
1361 rgbOriginal = true;
1362 curCol = qRgba(r: rEd->value(), g: gEd->value(), b: bEd->value(), a: currentAlpha());
1363
1364 rgb2hsv(rgb: currentColor(), h&: hue, s&: sat, v&: val);
1365
1366 hEd->setValue(hue);
1367 sEd->setValue(sat);
1368 vEd->setValue(val);
1369
1370 htEd->setText(QColor(curCol).name());
1371
1372 showCurrentColor();
1373 emit newCol(rgb: currentColor());
1374 updateQColor();
1375}
1376
1377void QColorShower::hsvEd()
1378{
1379 rgbOriginal = false;
1380 hue = hEd->value();
1381 sat = sEd->value();
1382 val = vEd->value();
1383
1384 QColor c;
1385 c.setHsv(h: hue, s: sat, v: val);
1386 curCol = c.rgb();
1387
1388 rEd->setValue(qRed(rgb: currentColor()));
1389 gEd->setValue(qGreen(rgb: currentColor()));
1390 bEd->setValue(qBlue(rgb: currentColor()));
1391
1392 htEd->setText(c.name());
1393
1394 showCurrentColor();
1395 emit newCol(rgb: currentColor());
1396 updateQColor();
1397}
1398
1399void QColorShower::htmlEd()
1400{
1401 QString t = htEd->text();
1402 if (t.isEmpty())
1403 return;
1404
1405 if (!t.startsWith(s: u"#")) {
1406 t.prepend(v: u"#");
1407 QSignalBlocker blocker(htEd);
1408 htEd->setText(t);
1409 }
1410
1411 QColor c = QColor::fromString(name: t);
1412 if (!c.isValid())
1413 return;
1414
1415 curCol = qRgba(r: c.red(), g: c.green(), b: c.blue(), a: currentAlpha());
1416 rgb2hsv(rgb: curCol, h&: hue, s&: sat, v&: val);
1417
1418 hEd->setValue(hue);
1419 sEd->setValue(sat);
1420 vEd->setValue(val);
1421
1422 rEd->setValue(qRed(rgb: currentColor()));
1423 gEd->setValue(qGreen(rgb: currentColor()));
1424 bEd->setValue(qBlue(rgb: currentColor()));
1425
1426 showCurrentColor();
1427 emit newCol(rgb: currentColor());
1428 updateQColor();
1429}
1430
1431void QColorShower::setRgb(QRgb rgb)
1432{
1433 rgbOriginal = true;
1434 curCol = rgb;
1435
1436 rgb2hsv(rgb: currentColor(), h&: hue, s&: sat, v&: val);
1437
1438 hEd->setValue(hue);
1439 sEd->setValue(sat);
1440 vEd->setValue(val);
1441
1442 rEd->setValue(qRed(rgb: currentColor()));
1443 gEd->setValue(qGreen(rgb: currentColor()));
1444 bEd->setValue(qBlue(rgb: currentColor()));
1445
1446 htEd->setText(QColor(rgb).name());
1447
1448 showCurrentColor();
1449 updateQColor();
1450}
1451
1452void QColorShower::setHsv(int h, int s, int v)
1453{
1454 if (h < -1 || (uint)s > 255 || (uint)v > 255)
1455 return;
1456
1457 rgbOriginal = false;
1458 hue = h; val = v; sat = s;
1459 QColor c;
1460 c.setHsv(h: hue, s: sat, v: val);
1461 curCol = c.rgb();
1462
1463 hEd->setValue(hue);
1464 sEd->setValue(sat);
1465 vEd->setValue(val);
1466
1467 rEd->setValue(qRed(rgb: currentColor()));
1468 gEd->setValue(qGreen(rgb: currentColor()));
1469 bEd->setValue(qBlue(rgb: currentColor()));
1470
1471 htEd->setText(c.name());
1472
1473 showCurrentColor();
1474 updateQColor();
1475}
1476
1477void QColorShower::retranslateStrings()
1478{
1479 lblHue->setText(QColorDialog::tr(s: "Hu&e:"));
1480 lblSat->setText(QColorDialog::tr(s: "&Sat:"));
1481 lblVal->setText(QColorDialog::tr(s: "&Val:"));
1482 lblRed->setText(QColorDialog::tr(s: "&Red:"));
1483 lblGreen->setText(QColorDialog::tr(s: "&Green:"));
1484 lblBlue->setText(QColorDialog::tr(s: "Bl&ue:"));
1485 alphaLab->setText(QColorDialog::tr(s: "A&lpha channel:"));
1486 lblHtml->setText(QColorDialog::tr(s: "&HTML:"));
1487}
1488
1489void QColorShower::updateQColor()
1490{
1491 QColor oldQColor(curQColor);
1492 curQColor.setRgba(qRgba(r: qRed(rgb: curCol), g: qGreen(rgb: curCol), b: qBlue(rgb: curCol), a: currentAlpha()));
1493 if (curQColor != oldQColor)
1494 emit currentColorChanged(color: curQColor);
1495}
1496
1497//sets all widgets to display h,s,v
1498void QColorDialogPrivate::newHsv(int h, int s, int v)
1499{
1500 if (!nativeDialogInUse) {
1501 cs->setHsv(h, s, v);
1502 cp->setCol(h, s);
1503 lp->setCol(h, s, v);
1504 }
1505}
1506
1507//sets all widgets to display rgb
1508void QColorDialogPrivate::setCurrentRgbColor(QRgb rgb)
1509{
1510 if (!nativeDialogInUse) {
1511 cs->setRgb(rgb);
1512 newColorTypedIn(rgb);
1513 }
1514}
1515
1516// hack; doesn't keep curCol in sync, so use with care
1517void QColorDialogPrivate::setCurrentQColor(const QColor &color)
1518{
1519 Q_Q(QColorDialog);
1520 if (cs->curQColor != color) {
1521 cs->curQColor = color;
1522 emit q->currentColorChanged(color);
1523 }
1524}
1525
1526// size of standard and custom color selector
1527enum {
1528 colorColumns = 8,
1529 standardColorRows = 6,
1530 customColorRows = 2
1531};
1532
1533bool QColorDialogPrivate::selectColor(const QColor &col)
1534{
1535 QRgb color = col.rgb();
1536 // Check standard colors
1537 if (standard) {
1538 const QRgb *standardColors = QColorDialogOptions::standardColors();
1539 const QRgb *standardColorsEnd = standardColors + standardColorRows * colorColumns;
1540 const QRgb *match = std::find(first: standardColors, last: standardColorsEnd, val: color);
1541 if (match != standardColorsEnd) {
1542 const int index = int(match - standardColors);
1543 const int column = index / standardColorRows;
1544 const int row = index % standardColorRows;
1545 newStandard(row, column);
1546 standard->setCurrent(row, col: column);
1547 standard->setSelected(row, col: column);
1548 standard->setFocus();
1549 return true;
1550 }
1551 }
1552 // Check custom colors
1553 if (custom) {
1554 const QRgb *customColors = QColorDialogOptions::customColors();
1555 const QRgb *customColorsEnd = customColors + customColorRows * colorColumns;
1556 const QRgb *match = std::find(first: customColors, last: customColorsEnd, val: color);
1557 if (match != customColorsEnd) {
1558 const int index = int(match - customColors);
1559 const int column = index / customColorRows;
1560 const int row = index % customColorRows;
1561 newCustom(row, column);
1562 custom->setCurrent(row, col: column);
1563 custom->setSelected(row, col: column);
1564 custom->setFocus();
1565 return true;
1566 }
1567 }
1568 return false;
1569}
1570
1571QColor QColorDialogPrivate::grabScreenColor(const QPoint &p)
1572{
1573 QScreen *screen = QGuiApplication::screenAt(point: p);
1574 if (!screen)
1575 screen = QGuiApplication::primaryScreen();
1576 const QRect screenRect = screen->geometry();
1577 const QPixmap pixmap =
1578 screen->grabWindow(window: 0, x: p.x() - screenRect.x(), y: p.y() - screenRect.y(), w: 1, h: 1);
1579 const QImage i = pixmap.toImage();
1580 return i.pixel(x: 0, y: 0);
1581}
1582
1583//sets all widgets except cs to display rgb
1584void QColorDialogPrivate::newColorTypedIn(QRgb rgb)
1585{
1586 if (!nativeDialogInUse) {
1587 int h, s, v;
1588 rgb2hsv(rgb, h, s, v);
1589 cp->setCol(h, s);
1590 lp->setCol(h, s, v);
1591 }
1592}
1593
1594void QColorDialogPrivate::nextCustom(int r, int c)
1595{
1596 nextCust = r + customColorRows * c;
1597}
1598
1599void QColorDialogPrivate::newCustom(int r, int c)
1600{
1601 const int i = r + customColorRows * c;
1602 setCurrentRgbColor(QColorDialogOptions::customColor(index: i));
1603 if (standard)
1604 standard->setSelected(row: -1,col: -1);
1605}
1606
1607void QColorDialogPrivate::newStandard(int r, int c)
1608{
1609 setCurrentRgbColor(QColorDialogOptions::standardColor(index: r + c * 6));
1610 if (custom)
1611 custom->setSelected(row: -1,col: -1);
1612}
1613
1614void QColorDialogPrivate::pickScreenColor()
1615{
1616 Q_Q(QColorDialog);
1617
1618 auto *platformServices = QGuiApplicationPrivate::platformIntegration()->services();
1619 if (platformServices && platformServices->hasCapability(capability: QPlatformServices::Capability::ColorPicking)) {
1620 if (auto *colorPicker = platformServices->colorPicker(parent: q->windowHandle())) {
1621 q->connect(sender: colorPicker, signal: &QPlatformServiceColorPicker::colorPicked, context: q,
1622 slot: [q, colorPicker](const QColor &color) {
1623 colorPicker->deleteLater();
1624 q->setCurrentColor(color);
1625 });
1626 colorPicker->pickColor();
1627 return;
1628 }
1629 }
1630
1631 if (!colorPickingEventFilter)
1632 colorPickingEventFilter = new QColorPickingEventFilter(this, q);
1633 q->installEventFilter(filterObj: colorPickingEventFilter);
1634 QObject::connect(qApp, signal: &QGuiApplication::applicationStateChanged,
1635 context: colorPickingEventFilter, slot: &QColorPickingEventFilter::applicationStateChanged);
1636 // If user pushes Escape, the last color before picking will be restored.
1637 beforeScreenColorPicking = cs->currentColor();
1638#ifndef QT_NO_CURSOR
1639 q->grabMouse(Qt::CrossCursor);
1640#else
1641 q->grabMouse();
1642#endif
1643
1644#ifdef Q_OS_WIN32
1645 // On Windows mouse tracking doesn't work over other processes's windows
1646 updateTimer->start(30);
1647
1648 // HACK: Because mouse grabbing doesn't work across processes, we have to have a dummy,
1649 // invisible window to catch the mouse click, otherwise we will click whatever we clicked
1650 // and loose focus.
1651 dummyTransparentWindow.show();
1652#endif
1653 q->grabKeyboard();
1654 /* With setMouseTracking(true) the desired color can be more precisely picked up,
1655 * and continuously pushing the mouse button is not necessary.
1656 */
1657 q->setMouseTracking(true);
1658
1659 addCusBt->setDisabled(true);
1660 buttons->setDisabled(true);
1661 if (eyeDropperButton) {
1662 eyeDropperButton->setDisabled(true);
1663 const QPoint globalPos = QCursor::pos();
1664 q->setCurrentColor(grabScreenColor(p: globalPos));
1665 updateColorLabelText(globalPos);
1666 }
1667}
1668
1669void QColorDialogPrivate::updateColorLabelText(const QPoint &globalPos)
1670{
1671 if (lblScreenColorInfo)
1672 lblScreenColorInfo->setText(QColorDialog::tr(s: "Cursor at %1, %2\nPress ESC to cancel")
1673 .arg(a: globalPos.x())
1674 .arg(a: globalPos.y()));
1675}
1676
1677void QColorDialogPrivate::releaseColorPicking()
1678{
1679 Q_Q(QColorDialog);
1680 cp->setCrossVisible(true);
1681 q->removeEventFilter(obj: colorPickingEventFilter);
1682 QObject::disconnect(qApp, signal: &QGuiApplication::applicationStateChanged,
1683 receiver: colorPickingEventFilter, slot: &QColorPickingEventFilter::applicationStateChanged);
1684 q->releaseMouse();
1685#ifdef Q_OS_WIN32
1686 updateTimer->stop();
1687 dummyTransparentWindow.setVisible(false);
1688#endif
1689 q->releaseKeyboard();
1690 q->setMouseTracking(false);
1691 lblScreenColorInfo->setText("\n"_L1);
1692 addCusBt->setDisabled(false);
1693 buttons->setDisabled(false);
1694 eyeDropperButton->setDisabled(false);
1695}
1696
1697void QColorDialogPrivate::init(const QColor &initial)
1698{
1699 Q_Q(QColorDialog);
1700
1701 q->setSizeGripEnabled(false);
1702 q->setWindowTitle(QColorDialog::tr(s: "Select Color"));
1703
1704 // default: use the native dialog if possible. Can be overridden in setOptions()
1705 nativeDialogInUse = (platformColorDialogHelper() != nullptr);
1706 colorPickingEventFilter = nullptr;
1707 nextCust = 0;
1708
1709 if (!nativeDialogInUse)
1710 initWidgets();
1711
1712#ifdef Q_OS_WIN32
1713 dummyTransparentWindow.resize(1, 1);
1714 dummyTransparentWindow.setFlags(Qt::Tool | Qt::FramelessWindowHint);
1715#endif
1716
1717 q->setCurrentColor(initial);
1718}
1719
1720void QColorDialogPrivate::initWidgets()
1721{
1722 Q_Q(QColorDialog);
1723 QVBoxLayout *mainLay = new QVBoxLayout(q);
1724 // there's nothing in this dialog that benefits from sizing up
1725 mainLay->setSizeConstraint(QLayout::SetFixedSize);
1726
1727 QHBoxLayout *topLay = new QHBoxLayout();
1728 mainLay->addLayout(layout: topLay);
1729
1730 leftLay = nullptr;
1731
1732#if defined(QT_SMALL_COLORDIALOG)
1733 smallDisplay = true;
1734 const int lumSpace = 20;
1735#else
1736 // small displays (e.g. PDAs) cannot fit the full color dialog,
1737 // so just use the color picker.
1738 smallDisplay = (QGuiApplication::primaryScreen()->virtualGeometry().width() < 480 || QGuiApplication::primaryScreen()->virtualGeometry().height() < 350);
1739 const int lumSpace = topLay->spacing() / 2;
1740#endif
1741
1742 if (!smallDisplay) {
1743 leftLay = new QVBoxLayout;
1744 topLay->addLayout(layout: leftLay);
1745
1746 standard = new QColorWell(q, standardColorRows, colorColumns, QColorDialogOptions::standardColors());
1747 lblBasicColors = new QLabel(q);
1748#ifndef QT_NO_SHORTCUT
1749 lblBasicColors->setBuddy(standard);
1750#endif
1751 QObjectPrivate::connect(sender: standard, signal: &QColorWell::selected,
1752 receiverPrivate: this, slot: &QColorDialogPrivate::newStandard);
1753 leftLay->addWidget(lblBasicColors);
1754 leftLay->addWidget(standard);
1755
1756#if !defined(QT_SMALL_COLORDIALOG)
1757 if (supportsColorPicking()) {
1758 eyeDropperButton = new QPushButton();
1759 leftLay->addWidget(eyeDropperButton);
1760 lblScreenColorInfo = new QLabel("\n"_L1);
1761 leftLay->addWidget(lblScreenColorInfo);
1762 QObjectPrivate::connect(sender: eyeDropperButton, signal: &QPushButton::clicked,
1763 receiverPrivate: this, slot: &QColorDialogPrivate::pickScreenColor);
1764 } else {
1765 eyeDropperButton = nullptr;
1766 lblScreenColorInfo = nullptr;
1767 }
1768#endif
1769
1770 leftLay->addStretch();
1771
1772 custom = new QColorWell(q, customColorRows, colorColumns, QColorDialogOptions::customColors());
1773 custom->setAcceptDrops(true);
1774
1775 QObjectPrivate::connect(sender: custom, signal: &QColorWell::selected, receiverPrivate: this, slot: &QColorDialogPrivate::newCustom);
1776 QObjectPrivate::connect(sender: custom, signal: &QColorWell::currentChanged, receiverPrivate: this, slot: &QColorDialogPrivate::nextCustom);
1777
1778 QObject::connect(sender: custom, signal: &QWellArray::colorChanged, context: q, slot: [this] (int index, QRgb color) {
1779 QColorDialogOptions::setCustomColor(index, color);
1780 if (custom)
1781 custom->update();
1782 });
1783
1784 lblCustomColors = new QLabel(q);
1785#ifndef QT_NO_SHORTCUT
1786 lblCustomColors->setBuddy(custom);
1787#endif
1788 leftLay->addWidget(lblCustomColors);
1789 leftLay->addWidget(custom);
1790
1791 addCusBt = new QPushButton(q);
1792 QObjectPrivate::connect(sender: addCusBt, signal: &QPushButton::clicked, receiverPrivate: this, slot: &QColorDialogPrivate::addCustom);
1793 leftLay->addWidget(addCusBt);
1794 } else {
1795 // better color picker size for small displays
1796#if defined(QT_SMALL_COLORDIALOG)
1797 QSize screenSize = QGuiApplication::screenAt(QCursor::pos())->availableGeometry().size();
1798 pWidth = pHeight = qMin(screenSize.width(), screenSize.height());
1799 pHeight -= 20;
1800 if (screenSize.height() > screenSize.width())
1801 pWidth -= 20;
1802#else
1803 pWidth = 150;
1804 pHeight = 100;
1805#endif
1806 custom = nullptr;
1807 standard = nullptr;
1808 }
1809
1810 QVBoxLayout *rightLay = new QVBoxLayout;
1811 topLay->addLayout(layout: rightLay);
1812
1813 QHBoxLayout *pickLay = new QHBoxLayout;
1814 rightLay->addLayout(layout: pickLay);
1815
1816 QVBoxLayout *cLay = new QVBoxLayout;
1817 pickLay->addLayout(layout: cLay);
1818 cp = new QColorPicker(q);
1819
1820 cp->setFrameStyle(QFrame::Panel | QFrame::Sunken);
1821
1822#if defined(QT_SMALL_COLORDIALOG)
1823 cp->hide();
1824#else
1825 cLay->addSpacing(size: lumSpace);
1826 cLay->addWidget(cp);
1827#endif
1828 cLay->addSpacing(size: lumSpace);
1829
1830 lp = new QColorLuminancePicker(q);
1831#if defined(QT_SMALL_COLORDIALOG)
1832 lp->hide();
1833#else
1834 lp->setFixedWidth(20);
1835 pickLay->addSpacing(size: 10);
1836 pickLay->addWidget(lp);
1837 pickLay->addStretch();
1838#endif
1839
1840 QObject::connect(sender: cp, signal: &QColorPicker::newCol, context: lp, slot: qOverload<int, int>(&QColorLuminancePicker::setCol));
1841 QObjectPrivate::connect(sender: lp, signal: &QColorLuminancePicker::newHsv, receiverPrivate: this, slot: &QColorDialogPrivate::newHsv);
1842
1843 rightLay->addStretch();
1844
1845 cs = new QColorShower(q);
1846 pickLay->setContentsMargins(cs->gl->contentsMargins());
1847 QObjectPrivate::connect(sender: cs, signal: &QColorShower::newCol,
1848 receiverPrivate: this, slot: &QColorDialogPrivate::newColorTypedIn);
1849 QObject::connect(sender: cs, signal: &QColorShower::currentColorChanged,
1850 context: q, slot: &QColorDialog::currentColorChanged);
1851#if defined(QT_SMALL_COLORDIALOG)
1852 topLay->addWidget(cs);
1853#else
1854 rightLay->addWidget(cs);
1855 if (leftLay)
1856 leftLay->addSpacing(size: cs->gl->contentsMargins().right());
1857#endif
1858
1859 buttons = new QDialogButtonBox(q);
1860 mainLay->addWidget(buttons);
1861
1862 ok = buttons->addButton(button: QDialogButtonBox::Ok);
1863 QObject::connect(sender: ok, signal: &QPushButton::clicked, context: q, slot: &QColorDialog::accept);
1864 ok->setDefault(true);
1865 cancel = buttons->addButton(button: QDialogButtonBox::Cancel);
1866 QObject::connect(sender: cancel, signal: &QPushButton::clicked, context: q, slot: &QColorDialog::reject);
1867
1868#ifdef Q_OS_WIN32
1869 updateTimer = new QTimer(q);
1870 QObjectPrivate::connect(updateTimer, &QTimer::timeout,
1871 this, qOverload<>(&QColorDialogPrivate::updateColorPicking));
1872#endif
1873 retranslateStrings();
1874}
1875
1876void QColorDialogPrivate::initHelper(QPlatformDialogHelper *h)
1877{
1878 QColorDialog *d = q_func();
1879 auto *colorDialogHelper = static_cast<QPlatformColorDialogHelper*>(h);
1880 QObject::connect(sender: colorDialogHelper, signal: &QPlatformColorDialogHelper::currentColorChanged,
1881 context: d, slot: &QColorDialog::currentColorChanged);
1882 QObject::connect(sender: colorDialogHelper, signal: &QPlatformColorDialogHelper::colorSelected,
1883 context: d, slot: &QColorDialog::colorSelected);
1884 colorDialogHelper->setOptions(options);
1885}
1886
1887void QColorDialogPrivate::helperPrepareShow(QPlatformDialogHelper *)
1888{
1889 options->setWindowTitle(q_func()->windowTitle());
1890}
1891
1892void QColorDialogPrivate::addCustom()
1893{
1894 QColorDialogOptions::setCustomColor(index: nextCust, color: cs->currentColor());
1895 if (custom)
1896 custom->update();
1897 nextCust = (nextCust+1) % QColorDialogOptions::customColorCount();
1898}
1899
1900void QColorDialogPrivate::retranslateStrings()
1901{
1902 if (nativeDialogInUse)
1903 return;
1904
1905 if (!smallDisplay) {
1906 lblBasicColors->setText(QColorDialog::tr(s: "&Basic colors"));
1907 lblCustomColors->setText(QColorDialog::tr(s: "&Custom colors"));
1908 addCusBt->setText(QColorDialog::tr(s: "&Add to Custom Colors"));
1909#if !defined(QT_SMALL_COLORDIALOG)
1910 if (eyeDropperButton)
1911 eyeDropperButton->setText(QColorDialog::tr(s: "&Pick Screen Color"));
1912#endif
1913 }
1914
1915 cs->retranslateStrings();
1916}
1917
1918bool QColorDialogPrivate::supportsColorPicking() const
1919{
1920 const auto integration = QGuiApplicationPrivate::platformIntegration();
1921 return integration->hasCapability(cap: QPlatformIntegration::ScreenWindowGrabbing)
1922 || integration->services()->hasCapability(capability: QPlatformServices::Capability::ColorPicking);
1923}
1924
1925bool QColorDialogPrivate::canBeNativeDialog() const
1926{
1927 // Don't use Q_Q here! This function is called from ~QDialog,
1928 // so Q_Q calling q_func() invokes undefined behavior (invalid cast in q_func()).
1929 const QDialog * const q = static_cast<const QDialog*>(q_ptr);
1930 if (nativeDialogInUse)
1931 return true;
1932 if (QCoreApplication::testAttribute(attribute: Qt::AA_DontUseNativeDialogs)
1933 || q->testAttribute(attribute: Qt::WA_DontShowOnScreen)
1934 || (options->options() & QColorDialog::DontUseNativeDialog)) {
1935 return false;
1936 }
1937
1938 return strcmp(s1: QColorDialog::staticMetaObject.className(), s2: q->metaObject()->className()) == 0;
1939}
1940
1941static const Qt::WindowFlags qcd_DefaultWindowFlags =
1942 Qt::Dialog | Qt::WindowTitleHint
1943 | Qt::WindowSystemMenuHint | Qt::WindowCloseButtonHint;
1944
1945/*!
1946 \class QColorDialog
1947 \brief The QColorDialog class provides a dialog widget for specifying colors.
1948
1949 \ingroup standard-dialogs
1950 \inmodule QtWidgets
1951
1952 The color dialog's function is to allow users to choose colors.
1953 For example, you might use this in a drawing program to allow the
1954 user to set the brush color.
1955
1956 The static functions provide modal color dialogs.
1957 \omit
1958 If you require a modeless dialog, use the QColorDialog constructor.
1959 \endomit
1960
1961 The static getColor() function shows the dialog, and allows the user to
1962 specify a color. This function can also be used to let users choose a
1963 color with a level of transparency: pass the ShowAlphaChannel option as
1964 an additional argument.
1965
1966 The user can store customCount() different custom colors. The
1967 custom colors are shared by all color dialogs, and remembered
1968 during the execution of the program. Use setCustomColor() to set
1969 the custom colors, and use customColor() to get them.
1970
1971 When pressing the "Pick Screen Color" button, the cursor changes to a haircross
1972 and the colors on the screen are scanned. The user can pick up one by clicking
1973 the mouse or the Enter button. Pressing Escape restores the last color selected
1974 before entering this mode.
1975
1976 The \l{dialogs/standarddialogs}{Standard Dialogs} example shows
1977 how to use QColorDialog as well as other built-in Qt dialogs.
1978
1979 \image fusion-colordialog.png A color dialog in the Fusion widget style.
1980
1981 \sa QColor, QFileDialog, QFontDialog, {Standard Dialogs Example}
1982*/
1983
1984/*!
1985 Constructs a color dialog with the given \a parent.
1986*/
1987QColorDialog::QColorDialog(QWidget *parent)
1988 : QColorDialog(QColor(Qt::white), parent)
1989{
1990}
1991
1992/*!
1993 Constructs a color dialog with the given \a parent and specified
1994 \a initial color.
1995*/
1996QColorDialog::QColorDialog(const QColor &initial, QWidget *parent)
1997 : QDialog(*new QColorDialogPrivate, parent, qcd_DefaultWindowFlags)
1998{
1999 Q_D(QColorDialog);
2000 d->init(initial);
2001}
2002
2003void QColorDialogPrivate::setCurrentColor(const QColor &color, SetColorMode setColorMode)
2004{
2005 if (nativeDialogInUse) {
2006 platformColorDialogHelper()->setCurrentColor(color);
2007 return;
2008 }
2009
2010 if (setColorMode & ShowColor) {
2011 setCurrentRgbColor(color.rgb());
2012 setCurrentAlpha(color.alpha());
2013 }
2014 if (setColorMode & SelectColor)
2015 selectColor(col: color);
2016}
2017
2018/*!
2019 \property QColorDialog::currentColor
2020 \brief the currently selected color in the dialog
2021*/
2022
2023void QColorDialog::setCurrentColor(const QColor &color)
2024{
2025 Q_D(QColorDialog);
2026 d->setCurrentColor(color);
2027}
2028
2029QColor QColorDialog::currentColor() const
2030{
2031 Q_D(const QColorDialog);
2032 return d->currentQColor();
2033}
2034
2035/*!
2036 Returns the color that the user selected by clicking the \uicontrol{OK}
2037 or equivalent button.
2038
2039 \note This color is not always the same as the color held by the
2040 \l currentColor property since the user can choose different colors
2041 before finally selecting the one to use.
2042*/
2043QColor QColorDialog::selectedColor() const
2044{
2045 Q_D(const QColorDialog);
2046 return d->selectedQColor;
2047}
2048
2049/*!
2050 Sets the given \a option to be enabled if \a on is true;
2051 otherwise, clears the given \a option.
2052
2053 \sa options, testOption()
2054*/
2055void QColorDialog::setOption(ColorDialogOption option, bool on)
2056{
2057 const QColorDialog::ColorDialogOptions previousOptions = options();
2058 if (!(previousOptions & option) != !on)
2059 setOptions(previousOptions ^ option);
2060}
2061
2062/*!
2063 Returns \c true if the given \a option is enabled; otherwise, returns
2064 false.
2065
2066 \sa options, setOption()
2067*/
2068bool QColorDialog::testOption(ColorDialogOption option) const
2069{
2070 Q_D(const QColorDialog);
2071 return d->options->testOption(option: static_cast<QColorDialogOptions::ColorDialogOption>(option));
2072}
2073
2074/*!
2075 \property QColorDialog::options
2076 \brief the various options that affect the look and feel of the dialog
2077
2078 By default, all options are disabled.
2079
2080 Options should be set before showing the dialog. Setting them while the
2081 dialog is visible is not guaranteed to have an immediate effect on the
2082 dialog (depending on the option and on the platform).
2083
2084 \sa setOption(), testOption()
2085*/
2086void QColorDialog::setOptions(ColorDialogOptions options)
2087{
2088 Q_D(QColorDialog);
2089
2090 if (QColorDialog::options() == options)
2091 return;
2092
2093 d->options->setOptions(QColorDialogOptions::ColorDialogOptions(int(options)));
2094 if ((options & DontUseNativeDialog) && d->nativeDialogInUse) {
2095 d->nativeDialogInUse = false;
2096 d->initWidgets();
2097 }
2098 if (!d->nativeDialogInUse) {
2099 d->buttons->setVisible(!(options & NoButtons));
2100 d->showAlpha(b: options & ShowAlphaChannel);
2101 if (d->eyeDropperButton)
2102 d->eyeDropperButton->setVisible(!(options & NoEyeDropperButton));
2103 }
2104}
2105
2106QColorDialog::ColorDialogOptions QColorDialog::options() const
2107{
2108 Q_D(const QColorDialog);
2109 return QColorDialog::ColorDialogOptions(int(d->options->options()));
2110}
2111
2112/*!
2113 \enum QColorDialog::ColorDialogOption
2114
2115 This enum specifies various options that affect the look and feel
2116 of a color dialog.
2117
2118 \value ShowAlphaChannel Allow the user to select the alpha component of a color.
2119 \value NoButtons Don't display \uicontrol{OK} and \uicontrol{Cancel} buttons. (Useful for "live dialogs".)
2120 \value NoEyeDropperButton Hide the \uicontrol{Eye Dropper} button. This value was added in Qt 6.6.
2121 \value DontUseNativeDialog Use Qt's standard color dialog instead of the operating system
2122 native color dialog.
2123
2124 \sa options, setOption(), testOption(), windowModality()
2125*/
2126
2127/*!
2128 \fn void QColorDialog::currentColorChanged(const QColor &color)
2129
2130 This signal is emitted whenever the current color changes in the dialog.
2131 The current color is specified by \a color.
2132
2133 \sa color, colorSelected()
2134*/
2135
2136/*!
2137 \fn void QColorDialog::colorSelected(const QColor &color);
2138
2139 This signal is emitted just after the user has clicked \uicontrol{OK} to
2140 select a color to use. The chosen color is specified by \a color.
2141
2142 \sa color, currentColorChanged()
2143*/
2144
2145/*!
2146 Changes the visibility of the dialog. If \a visible is true, the dialog
2147 is shown; otherwise, it is hidden.
2148*/
2149void QColorDialog::setVisible(bool visible)
2150{
2151 // will call QColorDialogPrivate::setVisible override
2152 QDialog::setVisible(visible);
2153}
2154
2155/*!
2156 \internal
2157
2158 The implementation of QColorDialog::setVisible() has to live here so that the call
2159 to hide() in ~QDialog calls this function; it wouldn't call the override of
2160 QDialog::setVisible().
2161*/
2162void QColorDialogPrivate::setVisible(bool visible)
2163{
2164 // Don't use Q_Q here! This function is called from ~QDialog,
2165 // so Q_Q calling q_func() invokes undefined behavior (invalid cast in q_func()).
2166 const auto q = static_cast<QDialog *>(q_ptr);
2167
2168 if (visible)
2169 selectedQColor = QColor();
2170
2171 if (nativeDialogInUse) {
2172 if (setNativeDialogVisible(visible)) {
2173 // Set WA_DontShowOnScreen so that QDialog::setVisible(visible) below
2174 // updates the state correctly, but skips showing the non-native version:
2175 q->setAttribute(Qt::WA_DontShowOnScreen);
2176 } else if (visible) {
2177 initWidgets();
2178 }
2179 } else {
2180 q->setAttribute(Qt::WA_DontShowOnScreen, on: false);
2181 }
2182
2183 QDialogPrivate::setVisible(visible);
2184}
2185
2186/*!
2187 Opens the dialog and connects its colorSelected() signal to the slot specified
2188 by \a receiver and \a member.
2189
2190 The signal will be disconnected from the slot when the dialog is closed.
2191*/
2192void QColorDialog::open(QObject *receiver, const char *member)
2193{
2194 Q_D(QColorDialog);
2195 connect(sender: this, SIGNAL(colorSelected(QColor)), receiver, member);
2196 d->receiverToDisconnectOnClose = receiver;
2197 d->memberToDisconnectOnClose = member;
2198 QDialog::open();
2199}
2200
2201/*!
2202 Pops up a modal color dialog with the given window \a title (or "Select Color" if none is
2203 specified), lets the user choose a color, and returns that color. The color is initially set
2204 to \a initial. The dialog is a child of \a parent. It returns an invalid (see
2205 QColor::isValid()) color if the user cancels the dialog.
2206
2207 The \a options argument allows you to customize the dialog.
2208*/
2209QColor QColorDialog::getColor(const QColor &initial, QWidget *parent, const QString &title,
2210 ColorDialogOptions options)
2211{
2212 QAutoPointer<QColorDialog> dlg(new QColorDialog(parent));
2213 if (!title.isEmpty())
2214 dlg->setWindowTitle(title);
2215 dlg->setOptions(options);
2216 dlg->setCurrentColor(initial);
2217
2218 // If the dlg was deleted with a parent window,
2219 // dlg == nullptr after leaving the exec().
2220 dlg->exec();
2221 if (bool(dlg))
2222 return dlg->selectedColor();
2223 else
2224 return QColor();
2225}
2226
2227/*!
2228 Destroys the color dialog.
2229*/
2230
2231QColorDialog::~QColorDialog()
2232{
2233}
2234
2235/*!
2236 \reimp
2237*/
2238void QColorDialog::changeEvent(QEvent *e)
2239{
2240 Q_D(QColorDialog);
2241 if (e->type() == QEvent::LanguageChange)
2242 d->retranslateStrings();
2243 QDialog::changeEvent(e);
2244}
2245
2246void QColorDialogPrivate::updateColorPicking()
2247{
2248#ifndef QT_NO_CURSOR
2249 Q_Q(QColorDialog);
2250 static QPoint lastGlobalPos;
2251 QPoint newGlobalPos = QCursor::pos();
2252 if (lastGlobalPos == newGlobalPos)
2253 return;
2254 lastGlobalPos = newGlobalPos;
2255
2256 if (!q->rect().contains(p: q->mapFromGlobal(newGlobalPos))) { // Inside the dialog mouse tracking works, handleColorPickingMouseMove will be called
2257 updateColorPicking(pos: newGlobalPos);
2258#ifdef Q_OS_WIN32
2259 dummyTransparentWindow.setPosition(newGlobalPos);
2260#endif
2261 }
2262#endif // ! QT_NO_CURSOR
2263}
2264
2265void QColorDialogPrivate::updateColorPicking(const QPoint &globalPos)
2266{
2267 const QColor color = grabScreenColor(p: globalPos);
2268 // QTBUG-39792, do not change standard, custom color selectors while moving as
2269 // otherwise it is not possible to pre-select a custom cell for assignment.
2270 setCurrentColor(color, setColorMode: ShowColor);
2271 updateColorLabelText(globalPos);
2272}
2273
2274bool QColorDialogPrivate::handleColorPickingMouseMove(QMouseEvent *e)
2275{
2276 // If the cross is visible the grabbed color will be black most of the times
2277 cp->setCrossVisible(!cp->geometry().contains(p: e->position().toPoint()));
2278
2279 updateColorPicking(globalPos: e->globalPosition().toPoint());
2280 return true;
2281}
2282
2283bool QColorDialogPrivate::handleColorPickingMouseButtonRelease(QMouseEvent *e)
2284{
2285 setCurrentColor(color: grabScreenColor(p: e->globalPosition().toPoint()), setColorMode: SetColorAll);
2286 releaseColorPicking();
2287 return true;
2288}
2289
2290bool QColorDialogPrivate::handleColorPickingKeyPress(QKeyEvent *e)
2291{
2292 Q_Q(QColorDialog);
2293#if QT_CONFIG(shortcut)
2294 if (e->matches(key: QKeySequence::Cancel)) {
2295 releaseColorPicking();
2296 q->setCurrentColor(beforeScreenColorPicking);
2297 } else
2298#endif
2299 if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) {
2300 q->setCurrentColor(grabScreenColor(p: QCursor::pos()));
2301 releaseColorPicking();
2302 }
2303 e->accept();
2304 return true;
2305}
2306
2307/*!
2308 Closes the dialog and sets its result code to \a result. If this dialog
2309 is shown with exec(), done() causes the local event loop to finish,
2310 and exec() to return \a result.
2311
2312 \sa QDialog::done()
2313*/
2314void QColorDialog::done(int result)
2315{
2316 Q_D(QColorDialog);
2317 if (result == Accepted) {
2318 d->selectedQColor = d->currentQColor();
2319 emit colorSelected(color: d->selectedQColor);
2320 } else {
2321 d->selectedQColor = QColor();
2322 }
2323 QDialog::done(result);
2324 if (d->receiverToDisconnectOnClose) {
2325 disconnect(sender: this, SIGNAL(colorSelected(QColor)),
2326 receiver: d->receiverToDisconnectOnClose, member: d->memberToDisconnectOnClose);
2327 d->receiverToDisconnectOnClose = nullptr;
2328 }
2329 d->memberToDisconnectOnClose.clear();
2330}
2331
2332QT_END_NAMESPACE
2333
2334#include "qcolordialog.moc"
2335#include "moc_qcolordialog.cpp"
2336

source code of qtbase/src/widgets/dialogs/qcolordialog.cpp