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

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