From d928dbbc919f5f39af9ce5c69eb8e9ffa9da71d3 Mon Sep 17 00:00:00 2001 From: David Gil Date: Thu, 18 Apr 2013 01:05:41 +0200 Subject: Add a screen color picker button to QColorDialog Add a new button with which any color present on the screen can be picked up. This feature is very useful in any image processing application. Notice: --I have setMouseTracking to true because I consider that it makes much easier to grab the desired color. --I have set the cursor manually because for some unknown reason the cursor wouldn't change with grabMouse(Qt::CrossCursor). Task-number: QTBUG-14332 Change-Id: I39e3543d3ed55276f43d569a2f03087bbf89b27a Reviewed-by: Friedemann Kleint Reviewed-by: Kevin Ottens Reviewed-by: Lars Knoll --- src/widgets/dialogs/qcolordialog.cpp | 120 ++++++++++++++++++++++++++++++++++- src/widgets/dialogs/qcolordialog.h | 4 ++ src/widgets/dialogs/qcolordialog_p.h | 7 ++ 3 files changed, 130 insertions(+), 1 deletion(-) (limited to 'src') diff --git a/src/widgets/dialogs/qcolordialog.cpp b/src/widgets/dialogs/qcolordialog.cpp index d6254076c5..5edf883e5a 100644 --- a/src/widgets/dialogs/qcolordialog.cpp +++ b/src/widgets/dialogs/qcolordialog.cpp @@ -63,6 +63,8 @@ #include "qmimedata.h" #include "qspinbox.h" #include "qdialogbuttonbox.h" +#include "qscreen.h" +#include "qcursor.h" QT_BEGIN_NAMESPACE @@ -1417,6 +1419,15 @@ bool QColorDialogPrivate::selectColor(const QColor &col) return false; } +QColor QColorDialogPrivate::grabScreenColor(const QPoint &p) +{ + const QDesktopWidget *desktop = QApplication::desktop(); + const QPixmap pixmap = QGuiApplication::screens().at(desktop->screenNumber())->grabWindow(desktop->winId(), + p.x(), p.y(), 1, 1); + QImage i = pixmap.toImage(); + return i.pixel(0, 0); +} + //sets all widgets except cs to display rgb void QColorDialogPrivate::_q_newColorTypedIn(QRgb rgb) { @@ -1442,6 +1453,48 @@ void QColorDialogPrivate::_q_newStandard(int r, int c) custom->setSelected(-1,-1); } +void QColorDialogPrivate::_q_pickScreenColor() +{ + Q_Q(QColorDialog); + screenColorPicking = true; + // If user pushes Escape, the last color before picking will be restored. + beforeScreenColorPicking = cs->currentColor(); + /*For some reason, q->grabMouse(Qt::CrossCursor) doesn't change + * the cursor, and therefore I have to change it manually. + */ + q->grabMouse(); + q->setCursor(Qt::CrossCursor); + q->grabKeyboard(); + /* With setMouseTracking(true) the desired color can be more precisedly picked up, + * and continuously pushing the mouse button is not necessary. + */ + q->setMouseTracking(true); + + addCusBt->setDisabled(true); + buttons->setDisabled(true); + screenColorPickerButton->setDisabled(true); + + q->setCurrentColor(grabScreenColor(QCursor::pos())); + lblScreenColorInfo->setText(QColorDialog::tr("Cursor at %1, %2, color: %3\nPress ESC to cancel") + .arg(QCursor::pos().x()) + .arg(QCursor::pos().y()) + .arg(q->currentColor().name())); +} + +void QColorDialogPrivate::releaseColorPicking() +{ + Q_Q(QColorDialog); + screenColorPicking = false; + q->releaseMouse(); + q->releaseKeyboard(); + q->setCursor(Qt::ArrowCursor); + q->setMouseTracking(false); + lblScreenColorInfo->setText(QLatin1String("\n")); + addCusBt->setDisabled(false); + buttons->setDisabled(false); + screenColorPickerButton->setDisabled(false); +} + void QColorDialogPrivate::init(const QColor &initial) { Q_Q(QColorDialog); @@ -1450,7 +1503,7 @@ void QColorDialogPrivate::init(const QColor &initial) q->setWindowTitle(QColorDialog::tr("Select Color")); nativeDialogInUse = (platformColorDialogHelper() != 0); - + screenColorPicking = false; nextCust = 0; QVBoxLayout *mainLay = new QVBoxLayout(q); // there's nothing in this dialog that benefits from sizing up @@ -1486,6 +1539,15 @@ void QColorDialogPrivate::init(const QColor &initial) leftLay->addWidget(lblBasicColors); leftLay->addWidget(standard); +#if !defined(Q_OS_WINCE) && !defined(QT_SMALL_COLORDIALOG) + // The screen color picker button + screenColorPickerButton = new QPushButton(QColorDialog::tr("Pick Screen Color")); + leftLay->addWidget(screenColorPickerButton); + lblScreenColorInfo = new QLabel(QLatin1String("\n")); + leftLay->addWidget(lblScreenColorInfo); + q->connect(screenColorPickerButton, SIGNAL(clicked()), SLOT(_q_pickScreenColor())); +#endif + #if !defined(Q_OS_WINCE) leftLay->addStretch(); #endif @@ -1658,6 +1720,11 @@ static const Qt::WindowFlags DefaultWindowFlags = during the execution of the program. Use setCustomColor() to set the custom colors, and use customColor() to get them. + When pressing the "Pick Screen Color" button, the cursor changes to a haircross + and the colors on the screen are scanned. The user can pick up one by clicking + the mouse or the Enter button. Pressing Escape restores the last color selected + before entering this mode. + The \l{dialogs/standarddialogs}{Standard Dialogs} example shows how to use QColorDialog as well as other built-in Qt dialogs. @@ -1971,6 +2038,57 @@ void QColorDialog::changeEvent(QEvent *e) QDialog::changeEvent(e); } +/*! + \reimp +*/ +void QColorDialog::mouseMoveEvent(QMouseEvent *e) +{ + Q_D(QColorDialog); + if (d->screenColorPicking) { + setCurrentColor(d->grabScreenColor(e->globalPos())); + d->lblScreenColorInfo->setText(QColorDialog::tr("Cursor at %1, %2, color: %3\nPress ESC to cancel") + .arg(e->globalPos().x()) + .arg(e->globalPos().y()) + .arg(currentColor().name())); + return; + } + QDialog::mouseMoveEvent(e); +} + +/*! + \reimp +*/ +void QColorDialog::mouseReleaseEvent(QMouseEvent *e) +{ + Q_D(QColorDialog); + if (d->screenColorPicking) { + setCurrentColor(d->grabScreenColor(e->globalPos())); + d->releaseColorPicking(); + return; + } + QDialog::mouseReleaseEvent(e); +} + +/*! + \reimp +*/ +void QColorDialog::keyPressEvent(QKeyEvent *e) +{ + Q_D(QColorDialog); + if (d->screenColorPicking) { + if (e->key() == Qt::Key_Escape) { + d->releaseColorPicking(); + d->setCurrentColor(d->beforeScreenColorPicking); + } else if (e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { + setCurrentColor(d->grabScreenColor(QCursor::pos())); + d->releaseColorPicking(); + } + e->accept(); + return; + } + QDialog::keyPressEvent(e); +} + /*! Closes the dialog and sets its result code to \a result. If this dialog is shown with exec(), done() causes the local event loop to finish, diff --git a/src/widgets/dialogs/qcolordialog.h b/src/widgets/dialogs/qcolordialog.h index 80a31c4268..e76a120c3a 100644 --- a/src/widgets/dialogs/qcolordialog.h +++ b/src/widgets/dialogs/qcolordialog.h @@ -112,6 +112,9 @@ Q_SIGNALS: protected: void changeEvent(QEvent *event); + virtual void mouseMoveEvent(QMouseEvent *); + virtual void mouseReleaseEvent(QMouseEvent *); + virtual void keyPressEvent(QKeyEvent *); void done(int result); private: @@ -122,6 +125,7 @@ private: Q_PRIVATE_SLOT(d_func(), void _q_newColorTypedIn(QRgb rgb)) Q_PRIVATE_SLOT(d_func(), void _q_newCustom(int, int)) Q_PRIVATE_SLOT(d_func(), void _q_newStandard(int, int)) + Q_PRIVATE_SLOT(d_func(), void _q_pickScreenColor()) friend class QColorShower; }; diff --git a/src/widgets/dialogs/qcolordialog_p.h b/src/widgets/dialogs/qcolordialog_p.h index 900b38fc61..bb24992512 100644 --- a/src/widgets/dialogs/qcolordialog_p.h +++ b/src/widgets/dialogs/qcolordialog_p.h @@ -87,6 +87,7 @@ public: void setCurrentColor(QRgb rgb); void setCurrentQColor(const QColor &color); bool selectColor(const QColor &color); + QColor grabScreenColor(const QPoint &p); int currentAlpha() const; void setCurrentAlpha(int a); @@ -100,6 +101,8 @@ public: void _q_newColorTypedIn(QRgb rgb); void _q_newCustom(int, int); void _q_newStandard(int, int); + void _q_pickScreenColor(); + void releaseColorPicking(); QWellArray *custom; QWellArray *standard; @@ -111,12 +114,16 @@ public: QColorShower *cs; QLabel *lblBasicColors; QLabel *lblCustomColors; + QLabel *lblScreenColorInfo; QPushButton *ok; QPushButton *cancel; QPushButton *addCusBt; + QPushButton *screenColorPickerButton; QColor selectedQColor; int nextCust; bool smallDisplay; + bool screenColorPicking; + QRgb beforeScreenColorPicking; QSharedPointer options; QPointer receiverToDisconnectOnClose; -- cgit v1.2.3