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