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