44#include <QStyleOptionToolButton>
45#include <QWidgetAction>
47#include "moc_qgscolorbutton.cpp"
49using namespace Qt::StringLiterals;
52 : QToolButton( parent )
53 , mColorDialogTitle( cdt.isEmpty() ? tr(
"Select Color" ) : cdt )
54 , mNoColorString( tr(
"No color" ) )
55 , mOpaqueColorString( tr(
"Opaque color" ) )
60 setAcceptDrops(
true );
61 setMinimumSize( QSize( 24, 16 ) );
62 connect(
this, &QAbstractButton::clicked,
this, &QgsColorButton::buttonClicked );
65 mMenu =
new QMenu(
this );
66 connect( mMenu, &QMenu::aboutToShow,
this, &QgsColorButton::prepareMenu );
68 setPopupMode( QToolButton::MenuButtonPopup );
71 mMinimumSize = QSize( 120, 22 );
73 mMinimumSize = QSize( 120, 28 );
76 mMinimumSize.setHeight( std::max(
static_cast<int>(
Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 1.1 ), mMinimumSize.height() ) );
94 static QPixmap sTranspBkgrd;
96 if ( sTranspBkgrd.isNull() )
102void QgsColorButton::showColorDialog()
107 const QColor currentColor =
color();
112 if ( currentColor.isValid() )
123 const QgsSettings settings;
130 newColor = QColorDialog::getColor(
color(),
this, mColorDialogTitle, mAllowOpacity ? QColorDialog::ShowAlphaChannel : ( QColorDialog::ColorDialogOption ) 0 );
134 QgsColorDialog dialog(
this, Qt::WindowFlags(),
color() );
135 dialog.setTitle( mColorDialogTitle );
136 dialog.setAllowOpacity( mAllowOpacity );
140 newColor = dialog.color();
144 if ( newColor.isValid() )
146 setValidColor( newColor );
155 if ( !mDefaultColor.isValid() )
177 if ( e->type() == QEvent::ToolTip && isEnabled() )
179 QColor
c = linkedProjectColor();
180 const bool isProjectColor =
c.isValid();
181 if ( !isProjectColor )
184 QString info = ( isProjectColor ? u
"<p>%1: %2</p>"_s.arg( tr(
"Linked color" ), mLinkedColorName ) : QString() );
190 return QToolButton::event( e );
195 QColor noColor = QColor( mColor );
196 noColor.setAlpha( 0 );
202 QColor opaqueColor = QColor( mColor );
203 opaqueColor.setAlpha( 255 );
216 if ( e->button() == Qt::RightButton )
218 QToolButton::showMenu();
221 else if ( e->button() == Qt::LeftButton )
223 mDragStartPosition = e->pos();
225 QToolButton::mousePressEvent( e );
228bool QgsColorButton::colorFromMimeData(
const QMimeData *mimeData, QColor &resultColor )
233 bool hasAlpha =
false;
236 if ( mimeColor.isValid() )
238 if ( !mAllowOpacity )
241 mimeColor.setAlpha( 255 );
243 else if ( !hasAlpha )
246 mimeColor.setAlpha( mColor.alpha() );
248 resultColor = mimeColor;
266 QColor
c = linkedProjectColor();
270 if ( !( e->buttons() & Qt::LeftButton ) || !
c.isValid() )
273 QToolButton::mouseMoveEvent( e );
277 if ( ( e->pos() - mDragStartPosition ).manhattanLength() < QApplication::startDragDistance() )
280 QToolButton::mouseMoveEvent( e );
285 QDrag *drag =
new QDrag(
this );
288 drag->exec( Qt::CopyAction );
297 stopPicking( e->globalPos() );
302 QToolButton::mouseReleaseEvent( e );
305void QgsColorButton::stopPicking( QPoint eventPos,
bool samplingColor )
310 QgsApplication::restoreOverrideCursor();
311 setMouseTracking(
false );
312 mPickingColor =
false;
314 if ( !samplingColor )
322 addRecentColor( mColor );
325QColor QgsColorButton::linkedProjectColor()
const
327 QList<QgsProjectColorScheme *> projectSchemes;
329 if ( projectSchemes.length() > 0 )
331 QgsProjectColorScheme *scheme = projectSchemes.at( 0 );
333 for (
const auto &
color : colors )
335 if (
color.second.isEmpty() )
338 if (
color.second == mLinkedColorName )
349 if ( !mPickingColor )
352 QToolButton::keyPressEvent( e );
357 stopPicking( QCursor::pos(), e->key() == Qt::Key_Space );
362 const bool isProjectColor = linkedProjectColor().isValid();
363 if ( isProjectColor )
368 if ( colorFromMimeData( e->mimeData(), mimeColor ) )
373 e->acceptProposedAction();
387 const bool isProjectColor = linkedProjectColor().isValid();
388 if ( isProjectColor )
393 if ( colorFromMimeData( e->mimeData(), mimeColor ) )
396 e->acceptProposedAction();
398 addRecentColor( mimeColor );
404 if ( mAllowOpacity && isEnabled() && !
isNull() )
406 const double increment = ( (
event->modifiers() & Qt::ControlModifier ) ? 0.01 : 0.1 ) * (
event->angleDelta().y() > 0 ? 1 : -1 );
407 const double alpha = std::min( std::max( 0.0, mColor.alphaF() + increment ), 1.0 );
408 mColor.setAlphaF( alpha );
416 QToolButton::wheelEvent(
event );
420void QgsColorButton::setValidColor(
const QColor &newColor )
422 if ( newColor.isValid() )
425 addRecentColor( newColor );
429void QgsColorButton::setValidTemporaryColor(
const QColor &newColor )
431 if ( newColor.isValid() )
442 QPixmap pixmap( iconSize, iconSize );
443 pixmap.fill( Qt::transparent );
452 p.setPen( Qt::NoPen );
453 p.setBrush( checkBrush );
454 p.drawRect( 0, 0, iconSize - 1, iconSize - 1 );
458 p.setBrush( QBrush(
color ) );
461 p.setPen( QColor( 197, 197, 197 ) );
462 p.drawRect( 0, 0, iconSize - 1, iconSize - 1 );
467void QgsColorButton::buttonClicked()
469 if ( linkedProjectColor().isValid() )
471 QToolButton::showMenu();
487void QgsColorButton::prepareMenu()
495 const bool isProjectColor = linkedProjectColor().isValid();
497 if ( !isProjectColor )
501 QAction *nullAction =
new QAction( mNullColorString.isEmpty() ? tr(
"Clear Color" ) : mNullColorString,
this );
503 mMenu->addAction( nullAction );
508 if ( mDefaultColor.isValid() )
510 QAction *defaultColorAction =
new QAction( tr(
"Default Color" ),
this );
512 mMenu->addAction( defaultColorAction );
516 if ( mShowNoColorOption && mColor.alpha() > 0 )
518 QAction *noColorAction =
new QAction( mNoColorString,
this );
519 noColorAction->setIcon(
createMenuIcon( Qt::transparent,
false ) );
520 mMenu->addAction( noColorAction );
524 if ( ( mAllowOpacity || mShowNoColorOption ) && mColor.isValid() && mColor.alpha() < 255 )
526 QColor opaqueColor = QColor( mColor );
527 opaqueColor.setAlpha( 255 );
528 QAction *opaqueColorAction =
new QAction( mOpaqueColorString,
this );
530 mMenu->addAction( opaqueColorAction );
534 mMenu->addSeparator();
535 QgsColorWheel *colorWheel =
new QgsColorWheel( mMenu );
537 QgsColorWidgetAction *colorAction =
new QgsColorWidgetAction( colorWheel, mMenu, mMenu );
540 mMenu->addAction( colorAction );
545 QgsColorWidgetAction *alphaAction =
new QgsColorWidgetAction( alphaRamp, mMenu, mMenu );
550 mMenu->addAction( alphaAction );
553 if ( mColorSchemeRegistry )
557 QList<QgsColorScheme *>::iterator it = schemeList.begin();
558 for ( ; it != schemeList.end(); ++it )
560 QgsColorSwatchGridAction *colorAction =
new QgsColorSwatchGridAction( *it, mMenu, mContext,
this );
562 mMenu->addAction( colorAction );
568 mMenu->addSeparator();
571 if ( isProjectColor )
573 QAction *unlinkAction =
new QAction( tr(
"Unlink Color" ), mMenu );
574 mMenu->addAction( unlinkAction );
578 QAction *copyColorAction =
new QAction( tr(
"Copy Color" ),
this );
579 mMenu->addAction( copyColorAction );
582 if ( !isProjectColor )
584 QAction *pasteColorAction =
new QAction( tr(
"Paste Color" ),
this );
588 if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor ) )
594 pasteColorAction->setEnabled(
false );
596 mMenu->addAction( pasteColorAction );
599 QAction *pickColorAction =
new QAction( tr(
"Pick Color" ),
this );
600 mMenu->addAction( pickColorAction );
603 QAction *chooseColorAction =
new QAction( tr(
"Choose Color…" ),
this );
604 mMenu->addAction( chooseColorAction );
605 connect( chooseColorAction, &QAction::triggered,
this, &QgsColorButton::showColorDialog );
611 if ( e->type() == QEvent::EnabledChange )
615 QToolButton::changeEvent( e );
619void QgsColorButton::paintEvent( QPaintEvent *e )
621 QToolButton::paintEvent( e );
623 if ( !mBackgroundSet )
633 QToolButton::showEvent( e );
638 QToolButton::resizeEvent(
event );
646 const QColor oldColor = mColor;
650 if ( oldColor != mColor || ( mColor == QColor( Qt::black ) && !mColorSet ) )
663void QgsColorButton::addRecentColor(
const QColor &color )
670 QColor backgroundColor =
color;
671 bool isProjectColor =
false;
672 if ( !backgroundColor.isValid() && !mLinkedColorName.isEmpty() )
674 backgroundColor = linkedProjectColor();
675 isProjectColor = backgroundColor.isValid();
676 if ( !isProjectColor )
678 mLinkedColorName.clear();
682 if ( !backgroundColor.isValid() )
684 backgroundColor = mColor;
687 QSize currentIconSize;
691 if ( !mIconSize.isValid() )
694 QStyleOptionToolButton opt;
695 initStyleOption( &opt );
696 const QRect buttonSize = QApplication::style()->subControlRect( QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton,
this );
699 mIconSize = QSize( buttonSize.width() - 10, height() - 6 );
701 mIconSize = QSize( buttonSize.width() - 10, height() - 12 );
704 currentIconSize = mIconSize;
710 currentIconSize = QSize( width() - 10, height() - 6 );
712 currentIconSize = QSize( width() - 10, height() - 12 );
716 if ( !currentIconSize.isValid() || currentIconSize.width() <= 0 || currentIconSize.height() <= 0 )
722 const double pixelRatio = devicePixelRatioF();
723 QPixmap pixmap( currentIconSize * pixelRatio );
724 pixmap.setDevicePixelRatio( pixelRatio );
725 pixmap.fill( Qt::transparent );
727 if ( backgroundColor.isValid() )
729 const QRectF rect( 0, 0, currentIconSize.width(), currentIconSize.height() );
732 p.setRenderHint( QPainter::Antialiasing );
733 p.setPen( Qt::NoPen );
734 if ( mAllowOpacity && backgroundColor.alpha() < 255 )
738 p.setBrush( checkBrush );
739 p.drawRoundedRect( rect, 3, 3 );
742 p.setBrush( backgroundColor );
743 p.drawRoundedRect( rect, 3, 3 );
746 const QRectF clipRect( 0, 0,
static_cast<qreal
>( currentIconSize.width() ) / 2.0, currentIconSize.height() );
747 p.setClipRect( clipRect );
748 backgroundColor.setAlpha( 255 );
749 p.setBrush( backgroundColor );
750 p.drawRoundedRect( rect, 3, 3 );
754 p.setBrush( backgroundColor );
755 p.drawRoundedRect( rect, 3, 3 );
760 setIconSize( currentIconSize );
767 QColor
c = linkedProjectColor();
776 if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor ) )
780 addRecentColor( clipColor );
788 mCurrentColor = mColor;
792 mPickingColor =
true;
793 setMouseTracking(
true );
798 QColor
c = linkedProjectColor();
806 mAllowOpacity = allow;
811 mColorDialogTitle = title;
816 return mColorDialogTitle;
822 setMenu(
showMenu ? mMenu :
nullptr );
823 setPopupMode(
showMenu ? QToolButton::MenuButtonPopup : QToolButton::DelayedPopup );
836 mDefaultColor =
color;
842 mNullColorString = nullString;
852 return !mColor.isValid();
857 mLinkedColorName = name;
static const double UI_SCALE_FACTOR
UI scaling factor.
static QPixmap getThemePixmap(const QString &name, const QColor &foreColor=QColor(), const QColor &backColor=QColor(), int size=16)
Helper to get a theme icon as a pixmap.
static QCursor getThemeCursor(Cursor cursor)
Helper to get a theme cursor.
static QgsColorSchemeRegistry * colorSchemeRegistry()
Returns the application's color scheme registry, used for managing color schemes.
@ Sampler
Color/Value picker.
Registry of color schemes.
QList< QgsColorScheme * > schemes() const
Returns all color schemes in the registry.
@ ShowInColorButtonMenu
Show scheme in color button drop-down menu.
void setBaseColor(const QColor &baseColor)
Sets the base color for the color grid.
void colorChanged(const QColor &color)
Emitted when a color has been selected from the widget.
void setColor(const QColor &color, bool emitSignals=false) override
static QColor sampleColor(QPoint point)
Samples the color on screen at the specified global point (pixel).
QgsNamedColorList fetchColors(const QString &context=QString(), const QColor &baseColor=QColor()) override
Gets a list of colors from the scheme.
static QgsProject * instance()
Returns the QgsProject singleton instance.
void projectColorsChanged()
Emitted whenever the project's color scheme has been changed.
static void addRecentColor(const QColor &color)
Adds a color to the list of recent colors.
T value(const QString &dynamicKeyPart=QString()) const
Returns settings value.
static const QgsSettingsEntryBool * settingsNativeColorDialogs
Settings entry whether to use native color dialogs.
static QColor colorFromMimeData(const QMimeData *data, bool &hasAlpha)
Attempts to parse mime data as a color.
static std::unique_ptr< QMimeData > colorToMimeData(const QColor &color)
Creates mime data from a color.
QList< QPair< QColor, QString > > QgsNamedColorList
List of colors paired with a friendly display name identifying the color.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...
As part of the API refactoring and improvements which landed in the Processing API was substantially reworked from the x version This was done in order to allow much of the underlying Processing framework to be ported into c