diff --git a/python/gui/qgscolorbutton.sip b/python/gui/qgscolorbutton.sip index 68dff4cf91e..a41167912bd 100644 --- a/python/gui/qgscolorbutton.sip +++ b/python/gui/qgscolorbutton.sip @@ -88,14 +88,14 @@ class QgsColorButton: QPushButton public slots: /** - * Sets the background pixmap for the button based upon set color and transparency. + * Sets the background pixmap for the button based upon color and transparency. * Call directly to update background after adding/removing QColorDialog::ShowAlphaChannel option * but the color has not changed, i.e. setColor() wouldn't update button and * you want the button to retain the set color's alpha component regardless - * + * @param color Color for button background * @note added in 1.9 */ - void setButtonBackground(); + void setButtonBackground( QColor color = QColor() ); signals: /** @@ -112,7 +112,7 @@ class QgsColorButton: QPushButton void showEvent( QShowEvent* e ); static const QPixmap& transpBkgrd(); - /** + /** * Reimplemented to detect right mouse button clicks on the color button and allow dragging colors */ void mousePressEvent( QMouseEvent* e ); @@ -122,6 +122,16 @@ class QgsColorButton: QPushButton */ void mouseMoveEvent( QMouseEvent *e ); + /** + * Reimplemented to allow color picking + */ + void mouseReleaseEvent( QMouseEvent *e ); + + /** + * Reimplemented to allow cancelling color pick via keypress, and sample via space bar press + */ + void keyPressEvent( QKeyEvent *e ); + /** * Reimplemented to accept dragged colors */ diff --git a/src/gui/qgscolorbutton.cpp b/src/gui/qgscolorbutton.cpp index d3b7307c8ba..9d9f5124210 100644 --- a/src/gui/qgscolorbutton.cpp +++ b/src/gui/qgscolorbutton.cpp @@ -18,6 +18,7 @@ #include "qgsapplication.h" #include "qgslogger.h" #include "qgssymbollayerv2utils.h" +#include "qgscursors.h" #include #include @@ -26,6 +27,7 @@ #include #include #include +#include #ifdef Q_OS_WIN #include @@ -70,6 +72,7 @@ QgsColorButton::QgsColorButton( QWidget *parent, QString cdt, QColorDialog::Colo , mAcceptLiveUpdates( true ) , mTempPNG( NULL ) , mColorSet( false ) + , mPickingColor( false ) { setAcceptDrops( true ); connect( this, SIGNAL( clicked() ), this, SLOT( onButtonClicked() ) ); @@ -114,6 +117,13 @@ void QgsColorButton::onButtonClicked() void QgsColorButton::mousePressEvent( QMouseEvent *e ) { + if ( mPickingColor ) + { + //don't show dialog if in color picker mode + e->accept(); + return; + } + if ( e->button() == Qt::RightButton ) { showContextMenu( e ); @@ -174,6 +184,23 @@ bool QgsColorButton::colorFromMimeData( const QMimeData * mimeData, QColor& resu void QgsColorButton::mouseMoveEvent( QMouseEvent *e ) { + if ( mPickingColor ) + { + //currently in color picker mode + if ( e->buttons() & Qt::LeftButton ) + { + //if left button depressed, sample color under cursor and temporarily update button color + //to give feedback to user + QPixmap snappedPixmap = QPixmap::grabWindow( QApplication::desktop()->winId(), e->globalPos().x(), e->globalPos().y(), 1, 1 ); + QImage snappedImage = snappedPixmap.toImage(); + QColor hoverColor = snappedImage.pixel( 0, 0 ); + setButtonBackground( hoverColor ); + } + e->accept(); + return; + } + + //handle dragging colors from button if ( !( e->buttons() & Qt::LeftButton ) ) { QPushButton::mouseMoveEvent( e ); @@ -209,6 +236,52 @@ void QgsColorButton::mouseMoveEvent( QMouseEvent *e ) setDown( false ); } +void QgsColorButton::mouseReleaseEvent( QMouseEvent *e ) +{ + if ( mPickingColor ) + { + //end color picking operation by sampling the color under cursor + stopPicking( e->globalPos() ); + e->accept(); + return; + } + + QPushButton::mouseReleaseEvent( e ); +} + +void QgsColorButton::stopPicking( QPointF eventPos, bool sampleColor ) +{ + //release mouse and reset cursor + releaseMouse(); + unsetCursor(); + mPickingColor = false; + + if ( !sampleColor ) + { + //not sampling color, nothing more to do + return; + } + + //grab snapshot of pixel under mouse cursor + QPixmap snappedPixmap = QPixmap::grabWindow( QApplication::desktop()->winId(), eventPos.x(), eventPos.y(), 1, 1 ); + QImage snappedImage = snappedPixmap.toImage(); + //extract color from pixel and set color + setColor( snappedImage.pixel( 0, 0 ) ); +} + +void QgsColorButton::keyPressEvent( QKeyEvent *e ) +{ + if ( !mPickingColor ) + { + //if not picking a color, use default push button behaviour + QPushButton::keyPressEvent( e ); + return; + } + + //cancel picking, sampling the color if space was pressed + stopPicking( QCursor::pos(), e->key() == Qt::Key_Space ); +} + void QgsColorButton::dragEnterEvent( QDragEnterEvent *e ) { //is dragged data valid color data? @@ -238,8 +311,10 @@ void QgsColorButton::showContextMenu( QMouseEvent *event ) colorContextMenu.addAction( copyColorAction ); QAction* pasteColorAction = new QAction( tr( "Paste color" ), 0 ); pasteColorAction->setEnabled( false ); - colorContextMenu.addSeparator(); colorContextMenu.addAction( pasteColorAction ); + QAction* pickColorAction = new QAction( tr( "Pick color" ), 0 ); + colorContextMenu.addSeparator(); + colorContextMenu.addAction( pickColorAction ); QColor clipColor; if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor ) ) @@ -258,9 +333,18 @@ void QgsColorButton::showContextMenu( QMouseEvent *event ) //paste color setColor( clipColor ); } + else if ( selectedAction == pickColorAction ) + { + //pick color + QPixmap samplerPixmap = QPixmap(( const char ** ) sampler_cursor ); + setCursor( QCursor( samplerPixmap, 0, 0 ) ); + grabMouse(); + mPickingColor = true; + } delete copyColorAction; delete pasteColorAction; + delete pickColorAction; } void QgsColorButton::setValidColor( const QColor& newColor ) @@ -321,8 +405,12 @@ void QgsColorButton::setColor( const QColor &color ) mColorSet = true; } -void QgsColorButton::setButtonBackground() +void QgsColorButton::setButtonBackground( QColor color ) { + if ( !color.isValid() ) + { + color = mColor; + } if ( !text().isEmpty() ) { // generate icon pixmap for regular pushbutton @@ -355,11 +443,11 @@ void QgsColorButton::setButtonBackground() p.setRenderHint( QPainter::Antialiasing ); p.setClipPath( roundRect ); p.setPen( Qt::NoPen ); - if ( mColor.alpha() < 255 ) + if ( color.alpha() < 255 ) { p.drawTiledPixmap( rect, transpBkgrd() ); } - p.setBrush( mColor ); + p.setBrush( color ); p.drawRect( rect ); p.end(); @@ -381,12 +469,12 @@ void QgsColorButton::setButtonBackground() //QgsDebugMsg( QString( "%1 margin: %2" ).arg( objectName() ).arg( margin ) ); QString bkgrd = QString( " background-color: rgba(%1,%2,%3,%4);" ) - .arg( mColor.red() ) - .arg( mColor.green() ) - .arg( mColor.blue() ) - .arg( useAlpha ? mColor.alpha() : 255 ); + .arg( color.red() ) + .arg( color.green() ) + .arg( color.blue() ) + .arg( useAlpha ? color.alpha() : 255 ); - if ( useAlpha && mColor.alpha() < 255 ) + if ( useAlpha && color.alpha() < 255 ) { QPixmap pixmap = transpBkgrd(); QRect rect( 0, 0, pixmap.width(), pixmap.height() ); diff --git a/src/gui/qgscolorbutton.h b/src/gui/qgscolorbutton.h index a93ddb2835c..4ee8a9206ab 100644 --- a/src/gui/qgscolorbutton.h +++ b/src/gui/qgscolorbutton.h @@ -113,14 +113,14 @@ class GUI_EXPORT QgsColorButton: public QPushButton public slots: /** - * Sets the background pixmap for the button based upon set color and transparency. + * Sets the background pixmap for the button based upon color and transparency. * Call directly to update background after adding/removing QColorDialog::ShowAlphaChannel option * but the color has not changed, i.e. setColor() wouldn't update button and * you want the button to retain the set color's alpha component regardless - * + * @param color Color for button background * @note added in 1.9 */ - void setButtonBackground(); + void setButtonBackground( QColor color = QColor() ); signals: /** @@ -147,6 +147,16 @@ class GUI_EXPORT QgsColorButton: public QPushButton */ void mouseMoveEvent( QMouseEvent *e ); + /** + * Reimplemented to allow color picking + */ + void mouseReleaseEvent( QMouseEvent *e ); + + /** + * Reimplemented to allow cancelling color pick via keypress, and sample via space bar press + */ + void keyPressEvent( QKeyEvent *e ); + /** * Reimplemented to accept dragged colors */ @@ -166,6 +176,7 @@ class GUI_EXPORT QgsColorButton: public QPushButton bool mColorSet; // added in QGIS 2.1 QPoint mDragStartPosition; + bool mPickingColor; /** * Shows the color button context menu and handles copying and pasting color values. @@ -201,6 +212,15 @@ class GUI_EXPORT QgsColorButton: public QPushButton QString fullPath( const QString &path ); #endif + /** + * Ends a color picking operation + * @param eventPos global position of pixel to sample color from + * @param sampleColor set to true to actually sample the color, false to just cancel + * the color picking operation + * @note added in 2.5 + */ + void stopPicking( QPointF eventPos, bool sampleColor = true ); + private slots: void onButtonClicked(); diff --git a/src/gui/qgscursors.cpp b/src/gui/qgscursors.cpp index 6709ed5b000..d3bb474e3f0 100644 --- a/src/gui/qgscursors.cpp +++ b/src/gui/qgscursors.cpp @@ -180,3 +180,26 @@ const char *cross_hair_cursor[] = " +.+ " }; +const char *sampler_cursor[] = +{ + "16 16 3 1", + " » c None", + ".» c #000000", + "+» c #FFFFFF", + ".. ", + ".+. ", + " .+.. ", + " .++. ", + " .+++. ", + " .+++. ", + " .+++. ", + " .+++... ", + " .++... ", + " ...... ", + " ....... ", + " ........ ", + " .......", + " ......", + " .....", + " ... " +}; diff --git a/src/gui/qgscursors.h b/src/gui/qgscursors.h old mode 100644 new mode 100755 index 729a7bbfd62..3fe2151b291 --- a/src/gui/qgscursors.h +++ b/src/gui/qgscursors.h @@ -31,6 +31,7 @@ extern GUI_EXPORT const char *capture_point_cursor[]; extern GUI_EXPORT const char *select_cursor[]; extern GUI_EXPORT const char *identify_cursor[]; extern GUI_EXPORT const char *cross_hair_cursor[]; +extern GUI_EXPORT const char *sampler_cursor[]; #endif