From 2377688c6c16c2c521dde38dd6d8d38fad7d54c7 Mon Sep 17 00:00:00 2001 From: Nyall Dawson Date: Wed, 9 Dec 2015 16:07:22 +1100 Subject: [PATCH] Add QgsColorWidgetAction for easily inserting QgsColorWidgets in menus --- python/gui/qgscolorwidgets.sip | 64 ++++++++++++++++++++++++ src/gui/qgscolorwidgets.cpp | 91 ++++++++++++++++++++++++++++++++-- src/gui/qgscolorwidgets.h | 82 ++++++++++++++++++++++++++++++ 3 files changed, 233 insertions(+), 4 deletions(-) diff --git a/python/gui/qgscolorwidgets.sip b/python/gui/qgscolorwidgets.sip index ad8e6f75ecf..4e1b9e2f0bf 100644 --- a/python/gui/qgscolorwidgets.sip +++ b/python/gui/qgscolorwidgets.sip @@ -94,6 +94,11 @@ class QgsColorWidget : QWidget */ void colorChanged( const QColor &color ); + /** Emitted when mouse hovers over widget. + * @note added in QGIS 2.14 + */ + void hovered(); + protected: /** Returns the range of valid values for the color widget's component @@ -138,6 +143,63 @@ class QgsColorWidget : QWidget //Reimplemented to accept dropped colors void dropEvent( QDropEvent *e ); + + void mouseMoveEvent( QMouseEvent* e ); + void mousePressEvent( QMouseEvent* e ); + void mouseReleaseEvent( QMouseEvent* e ); +}; + + +/** \ingroup gui + * \class QgsColorWidgetAction + * An action containing a color widget, which can be embedded into a menu. + * @see QgsColorWidget + * @note introduced in QGIS 2.14 + */ + +class QgsColorWidgetAction: QWidgetAction +{ +%TypeHeaderCode +#include +%End + + public: + + /** Construct a new color widget action. + * @param colorWidget QgsColorWidget to show in action + * @param menu parent menu + * @param parent parent widget + */ + QgsColorWidgetAction( QgsColorWidget* colorWidget, QMenu* menu = 0, QWidget *parent /TransferThis/ = 0 ); + + virtual ~QgsColorWidgetAction(); + + /** Returns the color widget contained in the widget action. + */ + QgsColorWidget* colorWidget(); + + /** Sets whether the parent menu should be dismissed and closed when a color is selected + * from the action's color widget. + * @param dismiss set to true (default) to immediately close the menu when a color is selected + * from the widget. If set to false, the colorChanged signal will be emitted but the menu will + * stay open. + * @see dismissOnColorSelection() + */ + void setDismissOnColorSelection( bool dismiss ); + + /** Returns whether the parent menu will be dismissed after a color is selected from the + * action's color widget. + * @see setDismissOnColorSelection + */ + bool dismissOnColorSelection() const; + + signals: + + /** Emitted when a color has been selected from the widget + * @param color selected color + */ + void colorChanged( const QColor &color ); + }; @@ -163,6 +225,7 @@ class QgsColorWheel : QgsColorWidget virtual ~QgsColorWheel(); + virtual QSize sizeHint() const; void paintEvent( QPaintEvent* event ); public slots: @@ -394,6 +457,7 @@ class QgsColorPreviewWidget : QgsColorWidget virtual ~QgsColorPreviewWidget(); + virtual QSize sizeHint() const; void paintEvent( QPaintEvent* event ); /** Returns the secondary color for the widget diff --git a/src/gui/qgscolorwidgets.cpp b/src/gui/qgscolorwidgets.cpp index 4f18dde0bfa..95565e9ac7b 100644 --- a/src/gui/qgscolorwidgets.cpp +++ b/src/gui/qgscolorwidgets.cpp @@ -28,6 +28,7 @@ #include #include #include +#include "qgslogger.h" // @@ -221,6 +222,25 @@ void QgsColorWidget::dropEvent( QDropEvent *e ) //could not get color from mime data } +void QgsColorWidget::mouseMoveEvent( QMouseEvent *e ) +{ + emit hovered(); + e->accept(); + //don't pass to QWidget::mouseMoveEvent, causes issues with widget used in QWidgetAction +} + +void QgsColorWidget::mousePressEvent( QMouseEvent *e ) +{ + e->accept(); + //don't pass to QWidget::mousePressEvent, causes issues with widget used in QWidgetAction +} + +void QgsColorWidget::mouseReleaseEvent( QMouseEvent *e ) +{ + e->accept(); + //don't pass to QWidget::mouseReleaseEvent, causes issues with widget used in QWidgetAction +} + QColor QgsColorWidget::color() const { return mCurrentColor; @@ -378,6 +398,11 @@ QgsColorWheel::~QgsColorWheel() delete mWidgetImage; } +QSize QgsColorWheel::sizeHint() const +{ + return QSize( 200, 200 ); +} + void QgsColorWheel::paintEvent( QPaintEvent *event ) { Q_UNUSED( event ); @@ -585,6 +610,7 @@ void QgsColorWheel::setColorFromPos( const QPointF pos ) void QgsColorWheel::mouseMoveEvent( QMouseEvent *event ) { setColorFromPos( event->posF() ); + QgsColorWidget::mouseMoveEvent( event ); } void QgsColorWheel::mousePressEvent( QMouseEvent *event ) @@ -828,6 +854,7 @@ void QgsColorBox::resizeEvent( QResizeEvent *event ) void QgsColorBox::mouseMoveEvent( QMouseEvent *event ) { setColorFromPoint( event->pos() ); + QgsColorWidget::mouseMoveEvent( event ); } void QgsColorBox::mousePressEvent( QMouseEvent *event ) @@ -1148,6 +1175,7 @@ void QgsColorRampWidget::setMarkerSize( const int markerSize ) void QgsColorRampWidget::mouseMoveEvent( QMouseEvent *event ) { setColorFromPoint( event->posF() ); + QgsColorWidget::mouseMoveEvent( event ); } void QgsColorRampWidget::mousePressEvent( QMouseEvent *event ) @@ -1571,6 +1599,11 @@ void QgsColorPreviewWidget::paintEvent( QPaintEvent *event ) painter.end(); } +QSize QgsColorPreviewWidget::sizeHint() const +{ + return QSize( 200, 150 ); +} + void QgsColorPreviewWidget::setColor2( const QColor &color ) { if ( color == mColor2 ) @@ -1587,7 +1620,7 @@ void QgsColorPreviewWidget::mousePressEvent( QMouseEvent *e ) { mDragStartPosition = e->pos(); } - QWidget::mousePressEvent( e ); + QgsColorWidget::mousePressEvent( e ); } void QgsColorPreviewWidget::mouseReleaseEvent( QMouseEvent *e ) @@ -1595,7 +1628,7 @@ void QgsColorPreviewWidget::mouseReleaseEvent( QMouseEvent *e ) if (( e->pos() - mDragStartPosition ).manhattanLength() >= QApplication::startDragDistance() ) { //mouse moved, so a drag. nothing to do here - QWidget::mouseReleaseEvent( e ); + QgsColorWidget::mouseReleaseEvent( e ); return; } @@ -1621,14 +1654,14 @@ void QgsColorPreviewWidget::mouseMoveEvent( QMouseEvent *e ) if ( !( e->buttons() & Qt::LeftButton ) ) { //left button not depressed, so not a drag - QWidget::mouseMoveEvent( e ); + QgsColorWidget::mouseMoveEvent( e ); return; } if (( e->pos() - mDragStartPosition ).manhattanLength() < QApplication::startDragDistance() ) { //mouse not moved, so not a drag - QWidget::mouseMoveEvent( e ); + QgsColorWidget::mouseMoveEvent( e ); return; } @@ -1651,3 +1684,53 @@ void QgsColorPreviewWidget::mouseMoveEvent( QMouseEvent *e ) drag->setPixmap( createDragIcon( dragColor ) ); drag->exec( Qt::CopyAction ); } + + +// +// QgsColorWidgetAction +// + +QgsColorWidgetAction::QgsColorWidgetAction( QgsColorWidget* colorWidget, QMenu* menu, QWidget* parent ) + : QWidgetAction( parent ) + , mMenu( menu ) + , mColorWidget( colorWidget ) + , mSuppressRecurse( false ) + , mDismissOnColorSelection( true ) +{ + setDefaultWidget( mColorWidget ); + connect( mColorWidget, SIGNAL( colorChanged( QColor ) ), this, SLOT( setColor( QColor ) ) ); + + connect( this, SIGNAL( hovered() ), this, SLOT( onHover() ) ); + connect( mColorWidget, SIGNAL( hovered() ), this, SLOT( onHover() ) ); +} + +QgsColorWidgetAction::~QgsColorWidgetAction() +{ + +} + +void QgsColorWidgetAction::onHover() +{ + //see https://bugreports.qt-project.org/browse/QTBUG-10427?focusedCommentId=185610&page=com.atlassian.jira.plugin.system.issuetabpanels:comment-tabpanel#comment-185610 + if ( mSuppressRecurse ) + { + return; + } + + if ( mMenu ) + { + mSuppressRecurse = true; + mMenu->setActiveAction( this ); + mSuppressRecurse = false; + } +} + +void QgsColorWidgetAction::setColor( const QColor& color ) +{ + emit colorChanged( color ); + QAction::trigger(); + if ( mMenu && mDismissOnColorSelection ) + { + mMenu->hide(); + } +} diff --git a/src/gui/qgscolorwidgets.h b/src/gui/qgscolorwidgets.h index dd0bd232906..7c13ab50f21 100644 --- a/src/gui/qgscolorwidgets.h +++ b/src/gui/qgscolorwidgets.h @@ -16,6 +16,7 @@ #ifndef QGSCOLORWIDGETS_H #define QGSCOLORWIDGETS_H +#include #include class QColor; @@ -117,6 +118,11 @@ class GUI_EXPORT QgsColorWidget : public QWidget */ void colorChanged( const QColor &color ); + /** Emitted when mouse hovers over widget. + * @note added in QGIS 2.14 + */ + void hovered(); + protected: QColor mCurrentColor; @@ -170,9 +176,83 @@ class GUI_EXPORT QgsColorWidget : public QWidget //Reimplemented to accept dropped colors void dropEvent( QDropEvent *e ) override; + + void mouseMoveEvent( QMouseEvent* e ) override; + void mousePressEvent( QMouseEvent* e ) override; + void mouseReleaseEvent( QMouseEvent* e ) override; }; +/** \ingroup gui + * \class QgsColorWidgetAction + * An action containing a color widget, which can be embedded into a menu. + * @see QgsColorWidget + * @note introduced in QGIS 2.14 + */ + +class GUI_EXPORT QgsColorWidgetAction: public QWidgetAction +{ + Q_OBJECT + + public: + + /** Construct a new color widget action. + * @param colorWidget QgsColorWidget to show in action + * @param menu parent menu + * @param parent parent widget + */ + QgsColorWidgetAction( QgsColorWidget* colorWidget, QMenu* menu = 0, QWidget *parent = 0 ); + + virtual ~QgsColorWidgetAction(); + + /** Returns the color widget contained in the widget action. + */ + QgsColorWidget* colorWidget() { return mColorWidget; } + + /** Sets whether the parent menu should be dismissed and closed when a color is selected + * from the action's color widget. + * @param dismiss set to true (default) to immediately close the menu when a color is selected + * from the widget. If set to false, the colorChanged signal will be emitted but the menu will + * stay open. + * @see dismissOnColorSelection() + */ + void setDismissOnColorSelection( bool dismiss ) { mDismissOnColorSelection = dismiss; } + + /** Returns whether the parent menu will be dismissed after a color is selected from the + * action's color widget. + * @see setDismissOnColorSelection + */ + bool dismissOnColorSelection() const { return mDismissOnColorSelection; } + + signals: + + /** Emitted when a color has been selected from the widget + * @param color selected color + */ + void colorChanged( const QColor &color ); + + private: + QMenu* mMenu; + QgsColorWidget* mColorWidget; + + //used to supress recursion with hover events + bool mSuppressRecurse; + + bool mDismissOnColorSelection; + + private slots: + + /** Handles setting the active action for the menu when cursor hovers over color widget + */ + void onHover(); + + /** Emits color changed signal and closes parent menu + */ + void setColor( const QColor &color ); +}; + + + /** \ingroup gui * \class QgsColorWheel * A color wheel widget. This widget consists of an outer ring which allows for hue selection, and an @@ -193,6 +273,7 @@ class GUI_EXPORT QgsColorWheel : public QgsColorWidget virtual ~QgsColorWheel(); + virtual QSize sizeHint() const override; void paintEvent( QPaintEvent* event ) override; public slots: @@ -607,6 +688,7 @@ class GUI_EXPORT QgsColorPreviewWidget : public QgsColorWidget virtual ~QgsColorPreviewWidget(); void paintEvent( QPaintEvent* event ) override; + virtual QSize sizeHint() const override; /** Returns the secondary color for the widget * @returns secondary widget color, or an invalid color if the widget