diff --git a/python/gui/auto_generated/qgssymbolbutton.sip.in b/python/gui/auto_generated/qgssymbolbutton.sip.in index 73a88685190..4e9feb14a70 100644 --- a/python/gui/auto_generated/qgssymbolbutton.sip.in +++ b/python/gui/auto_generated/qgssymbolbutton.sip.in @@ -203,6 +203,10 @@ Emitted when the symbol's settings are changed. virtual void mouseMoveEvent( QMouseEvent *e ); + virtual void mouseReleaseEvent( QMouseEvent *e ); + + virtual void keyPressEvent( QKeyEvent *e ); + virtual void dragEnterEvent( QDragEnterEvent *e ); diff --git a/src/gui/qgssymbolbutton.cpp b/src/gui/qgssymbolbutton.cpp index 3b78581f9dd..5c5155f7c26 100644 --- a/src/gui/qgssymbolbutton.cpp +++ b/src/gui/qgssymbolbutton.cpp @@ -27,6 +27,8 @@ #include "qgsapplication.h" #include "qgsguiutils.h" #include "qgsexpressioncontextutils.h" +#include "qgsgui.h" +#include "qgscolordialog.h" #include #include @@ -236,6 +238,13 @@ void QgsSymbolButton::pasteColor() void QgsSymbolButton::mousePressEvent( QMouseEvent *e ) { + if ( mPickingColor ) + { + //don't show dialog if in color picker mode + e->accept(); + return; + } + if ( e->button() == Qt::RightButton ) { QToolButton::showMenu(); @@ -250,6 +259,13 @@ void QgsSymbolButton::mousePressEvent( QMouseEvent *e ) void QgsSymbolButton::mouseMoveEvent( QMouseEvent *e ) { + if ( mPickingColor ) + { + updatePreview( QgsGui::sampleColor( e->globalPos() ) ); + e->accept(); + return; + } + //handle dragging colors/symbols from button if ( !( e->buttons() & Qt::LeftButton ) ) @@ -274,6 +290,32 @@ void QgsSymbolButton::mouseMoveEvent( QMouseEvent *e ) setDown( false ); } +void QgsSymbolButton::mouseReleaseEvent( QMouseEvent *e ) +{ + if ( mPickingColor ) + { + //end color picking operation by sampling the color under cursor + stopPicking( e->globalPos() ); + e->accept(); + return; + } + + QToolButton::mouseReleaseEvent( e ); +} + +void QgsSymbolButton::keyPressEvent( QKeyEvent *e ) +{ + if ( !mPickingColor ) + { + //if not picking a color, use default tool button behavior + QToolButton::keyPressEvent( e ); + return; + } + + //cancel picking, sampling the color if space was pressed + stopPicking( QCursor::pos(), e->key() == Qt::Key_Space ); +} + void QgsSymbolButton::dragEnterEvent( QDragEnterEvent *e ) { //is dragged data valid color data? @@ -405,6 +447,14 @@ void QgsSymbolButton::prepareMenu() } mMenu->addAction( pasteColorAction ); connect( pasteColorAction, &QAction::triggered, this, &QgsSymbolButton::pasteColor ); + + QAction *pickColorAction = new QAction( tr( "Pick Color" ), this ); + mMenu->addAction( pickColorAction ); + connect( pickColorAction, &QAction::triggered, this, &QgsSymbolButton::activatePicker ); + + QAction *chooseColorAction = new QAction( tr( "Choose Color…" ), this ); + mMenu->addAction( chooseColorAction ); + connect( chooseColorAction, &QAction::triggered, this, &QgsSymbolButton::showColorDialog ); } void QgsSymbolButton::addRecentColor( const QColor &color ) @@ -412,6 +462,16 @@ void QgsSymbolButton::addRecentColor( const QColor &color ) QgsRecentColorScheme::addRecentColor( color ); } +void QgsSymbolButton::activatePicker() +{ + //activate picker color + QApplication::setOverrideCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::Sampler ) ); + grabMouse(); + grabKeyboard(); + mPickingColor = true; + setMouseTracking( true ); +} + void QgsSymbolButton::changeEvent( QEvent *e ) { @@ -535,6 +595,68 @@ QPixmap QgsSymbolButton::createColorIcon( const QColor &color ) const return pixmap; } +void QgsSymbolButton::stopPicking( QPoint eventPos, bool samplingColor ) +{ + //release mouse and keyboard, and reset cursor + releaseMouse(); + releaseKeyboard(); + QgsApplication::restoreOverrideCursor(); + setMouseTracking( false ); + mPickingColor = false; + + if ( !samplingColor ) + { + //not sampling color, restore old icon + updatePreview(); + return; + } + + const QColor newColor = QgsGui::sampleColor( eventPos ); + setColor( newColor ); + addRecentColor( newColor ); +} + +void QgsSymbolButton::showColorDialog() +{ + QgsPanelWidget *panel = QgsPanelWidget::findParentPanel( this ); + if ( panel && panel->dockMode() ) + { + QColor currentColor = mSymbol->color(); + QgsCompoundColorWidget *colorWidget = new QgsCompoundColorWidget( panel, currentColor, QgsCompoundColorWidget::LayoutVertical ); + colorWidget->setPanelTitle( tr( "Symbol Color" ) ); + colorWidget->setAllowOpacity( true ); + + if ( currentColor.isValid() ) + { + colorWidget->setPreviousColor( currentColor ); + } + + connect( colorWidget, &QgsCompoundColorWidget::currentColorChanged, this, [ = ]( const QColor & newColor ) + { + if ( newColor.isValid() ) + { + setColor( newColor ); + } + } ); + panel->openPanel( colorWidget ); + return; + } + + QColor newColor; + + QgsColorDialog dialog( this, nullptr, mSymbol->color() ); + dialog.setTitle( tr( "Symbol Color" ) ); + dialog.setAllowOpacity( true ); + + if ( dialog.exec() && dialog.color().isValid() ) + { + setColor( dialog.color() ); + } + + // reactivate button's window + activateWindow(); +} + void QgsSymbolButton::setDialogTitle( const QString &title ) { mDialogTitle = title; diff --git a/src/gui/qgssymbolbutton.h b/src/gui/qgssymbolbutton.h index b9be1c3de08..f55950caeb2 100644 --- a/src/gui/qgssymbolbutton.h +++ b/src/gui/qgssymbolbutton.h @@ -219,6 +219,8 @@ class GUI_EXPORT QgsSymbolButton : public QToolButton void mousePressEvent( QMouseEvent *e ) override; // Reimplemented to allow dragging colors/symbols from button void mouseMoveEvent( QMouseEvent *e ) override; + void mouseReleaseEvent( QMouseEvent *e ) override; + void keyPressEvent( QKeyEvent *e ) override; // Reimplemented to accept dragged colors void dragEnterEvent( QDragEnterEvent *e ) override; @@ -241,6 +243,11 @@ class GUI_EXPORT QgsSymbolButton : public QToolButton void addRecentColor( const QColor &color ); + /** + * Activates the color picker tool, which allows for sampling a color from anywhere on the screen + */ + void activatePicker(); + private: QSize mSizeHint; @@ -264,6 +271,8 @@ class GUI_EXPORT QgsSymbolButton : public QToolButton QgsExpressionContextGenerator *mExpressionContextGenerator = nullptr; + bool mPickingColor = false; + /** * Regenerates the text preview. If \a color is specified, a temporary color preview * is shown instead. @@ -286,6 +295,16 @@ class GUI_EXPORT QgsSymbolButton : public QToolButton */ QPixmap createColorIcon( const QColor &color ) const; + /** + * Ends a color picking operation + * \param eventPos global position of pixel to sample color from + * \param samplingColor set to TRUE to actually sample the color, FALSE to just cancel + * the color picking operation + */ + void stopPicking( QPoint eventPos, bool samplingColor = true ); + + void showColorDialog(); + }; #endif // QGSSYMBOLBUTTON_H