QGIS API Documentation  3.25.0-Master (10b47c2603)
qgscolorbutton.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgscolorbutton.cpp - Button which displays a color
3  --------------------------------------
4  Date : 12-Dec-2006
5  Copyright : (C) 2006 by Tom Elwertowski
6  Email : telwertowski at users dot sourceforge dot net
7  ***************************************************************************
8  * *
9  * This program is free software; you can redistribute it and/or modify *
10  * it under the terms of the GNU General Public License as published by *
11  * the Free Software Foundation; either version 2 of the License, or *
12  * (at your option) any later version. *
13  * *
14  ***************************************************************************/
15 
16 #include "qgscolorbutton.h"
17 #include "qgscolordialog.h"
18 #include "qgsapplication.h"
19 #include "qgslogger.h"
20 #include "qgssymbollayerutils.h"
21 #include "qgscolorswatchgrid.h"
22 #include "qgscolorschemeregistry.h"
23 #include "qgscolorwidgets.h"
24 #include "qgssettings.h"
25 #include "qgsproject.h"
26 #include "qgsguiutils.h"
27 #include "qgsgui.h"
28 
29 #include <QPainter>
30 #include <QMouseEvent>
31 #include <QMenu>
32 #include <QClipboard>
33 #include <QDrag>
34 #include <QStyle>
35 #include <QStyleOptionToolButton>
36 #include <QWidgetAction>
37 #include <QScreen>
38 #include <QLabel>
39 #include <QGridLayout>
40 #include <QPushButton>
41 #include <QBuffer>
42 
43 QgsColorButton::QgsColorButton( QWidget *parent, const QString &cdt, QgsColorSchemeRegistry *registry )
44  : QToolButton( parent )
45  , mColorDialogTitle( cdt.isEmpty() ? tr( "Select Color" ) : cdt )
46  , mNoColorString( tr( "No color" ) )
47 {
48  //if a color scheme registry was specified, use it, otherwise use the global instance
49  mColorSchemeRegistry = registry ? registry : QgsApplication::colorSchemeRegistry();
50 
51  setAcceptDrops( true );
52  setMinimumSize( QSize( 24, 16 ) );
53  connect( this, &QAbstractButton::clicked, this, &QgsColorButton::buttonClicked );
54 
55  //setup drop-down menu
56  mMenu = new QMenu( this );
57  connect( mMenu, &QMenu::aboutToShow, this, &QgsColorButton::prepareMenu );
58  setMenu( mMenu );
59  setPopupMode( QToolButton::MenuButtonPopup );
60 
61 #ifdef Q_OS_WIN
62  mMinimumSize = QSize( 120, 22 );
63 #else
64  mMinimumSize = QSize( 120, 28 );
65 #endif
66 
67  mMinimumSize.setHeight( std::max( static_cast<int>( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 1.1 ), mMinimumSize.height() ) );
68 
69  // If project colors change, we need to redraw the button, as it may be set to follow a project color
71  {
73  } );
74 }
75 
77 {
78  return mMinimumSize;
79 }
80 
82 {
83  return mMinimumSize;
84 }
85 
87 {
88  static QPixmap sTranspBkgrd;
89 
90  if ( sTranspBkgrd.isNull() )
91  sTranspBkgrd = QgsApplication::getThemePixmap( QStringLiteral( "/transp-background_8x8.png" ) );
92 
93  return sTranspBkgrd;
94 }
95 
96 void QgsColorButton::showColorDialog()
97 {
99  if ( panel && panel->dockMode() )
100  {
101  const QColor currentColor = color();
103  colorWidget->setPanelTitle( mColorDialogTitle );
104  colorWidget->setAllowOpacity( mAllowOpacity );
105 
106  if ( currentColor.isValid() )
107  {
108  colorWidget->setPreviousColor( currentColor );
109  }
110 
111  connect( colorWidget, &QgsCompoundColorWidget::currentColorChanged, this, &QgsColorButton::setValidTemporaryColor );
112  panel->openPanel( colorWidget );
113  return;
114  }
115 
116  QColor newColor;
117  const QgsSettings settings;
118 
119  // first check if we need to use the limited native dialogs
120  const bool useNative = settings.value( QStringLiteral( "qgis/native_color_dialogs" ), false ).toBool();
121  if ( useNative )
122  {
123  // why would anyone want this? who knows.... maybe the limited nature of native dialogs helps ease the transition for MapInfo users?
124  newColor = QColorDialog::getColor( color(), this, mColorDialogTitle, mAllowOpacity ? QColorDialog::ShowAlphaChannel : ( QColorDialog::ColorDialogOption )0 );
125  }
126  else
127  {
128  QgsColorDialog dialog( this, Qt::WindowFlags(), color() );
129  dialog.setTitle( mColorDialogTitle );
130  dialog.setAllowOpacity( mAllowOpacity );
131 
132  if ( dialog.exec() )
133  {
134  newColor = dialog.color();
135  }
136  }
137 
138  if ( newColor.isValid() )
139  {
140  setValidColor( newColor );
141  }
142 
143  // reactivate button's window
144  activateWindow();
145 }
146 
148 {
149  if ( !mDefaultColor.isValid() )
150  {
151  return;
152  }
153 
154  setColor( mDefaultColor );
155 }
156 
158 {
159  setColor( QColor() );
160  emit cleared();
161 }
162 
164 {
165  linkToProjectColor( QString() );
166  emit unlinked();
167 }
168 
169 bool QgsColorButton::event( QEvent *e )
170 {
171  if ( e->type() == QEvent::ToolTip )
172  {
173  QColor c = linkedProjectColor();
174  const bool isProjectColor = c.isValid();
175  if ( !isProjectColor )
176  c = mColor;
177 
178  const QString name = c.name();
179  const int hue = c.hue();
180  const int value = c.value();
181  const int saturation = c.saturation();
182 
183  // create very large preview swatch
184  const int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 23 );
185  const int height = static_cast< int >( width / 1.61803398875 ); // golden ratio
186 
187  const int margin = static_cast< int >( height * 0.1 );
188  QImage icon = QImage( width + 2 * margin, height + 2 * margin, QImage::Format_ARGB32 );
189  icon.fill( Qt::transparent );
190 
191  QPainter p;
192  p.begin( &icon );
193 
194  //start with checkboard pattern
195  const QBrush checkBrush = QBrush( transparentBackground() );
196  p.setPen( Qt::NoPen );
197  p.setBrush( checkBrush );
198  p.drawRect( margin, margin, width, height );
199 
200  //draw color over pattern
201  p.setBrush( QBrush( c ) );
202 
203  //draw border
204  p.setPen( QColor( 197, 197, 197 ) );
205  p.drawRect( margin, margin, width, height );
206  p.end();
207 
208  QByteArray data;
209  QBuffer buffer( &data );
210  icon.save( &buffer, "PNG", 100 );
211 
212  const QString info = ( isProjectColor ? QStringLiteral( "<p>%1: %2</p>" ).arg( tr( "Linked color" ), mLinkedColorName ) : QString() )
213  + QStringLiteral( "<b>HEX</b> %1<br>"
214  "<b>RGB</b> %2<br>"
215  "<b>HSV</b> %3,%4,%5<p>"
216  "<img src='data:image/png;base64, %0'>" ).arg( QString( data.toBase64() ), name,
218  .arg( hue ).arg( saturation ).arg( value );
219  setToolTip( info );
220  }
221  return QToolButton::event( e );
222 }
223 
225 {
226  QColor noColor = QColor( mColor );
227  noColor.setAlpha( 0 );
228  setColor( noColor );
229 }
230 
231 void QgsColorButton::mousePressEvent( QMouseEvent *e )
232 {
233  if ( mPickingColor )
234  {
235  //don't show dialog if in color picker mode
236  e->accept();
237  return;
238  }
239 
240  if ( e->button() == Qt::RightButton )
241  {
242  QToolButton::showMenu();
243  return;
244  }
245  else if ( e->button() == Qt::LeftButton )
246  {
247  mDragStartPosition = e->pos();
248  }
249  QToolButton::mousePressEvent( e );
250 }
251 
252 bool QgsColorButton::colorFromMimeData( const QMimeData *mimeData, QColor &resultColor )
253 {
254  bool hasAlpha = false;
255  QColor mimeColor = QgsSymbolLayerUtils::colorFromMimeData( mimeData, hasAlpha );
256 
257  if ( mimeColor.isValid() )
258  {
259  if ( !mAllowOpacity )
260  {
261  //remove alpha channel
262  mimeColor.setAlpha( 255 );
263  }
264  else if ( !hasAlpha )
265  {
266  //mime color has no explicit alpha component, so keep existing alpha
267  mimeColor.setAlpha( mColor.alpha() );
268  }
269  resultColor = mimeColor;
270  return true;
271  }
272 
273  //could not get color from mime data
274  return false;
275 }
276 
277 void QgsColorButton::mouseMoveEvent( QMouseEvent *e )
278 {
279  if ( mPickingColor )
280  {
281  setButtonBackground( QgsGui::sampleColor( e->globalPos() ) );
282  e->accept();
283  return;
284  }
285 
286  //handle dragging colors from button
287  QColor c = linkedProjectColor();
288  if ( !c.isValid() )
289  c = mColor;
290 
291  if ( !( e->buttons() & Qt::LeftButton ) || !c.isValid() )
292  {
293  //left button not depressed or no color set, so not a drag
294  QToolButton::mouseMoveEvent( e );
295  return;
296  }
297 
298  if ( ( e->pos() - mDragStartPosition ).manhattanLength() < QApplication::startDragDistance() )
299  {
300  //mouse not moved, so not a drag
301  QToolButton::mouseMoveEvent( e );
302  return;
303  }
304 
305  //user is dragging color
306  QDrag *drag = new QDrag( this );
307  drag->setMimeData( QgsSymbolLayerUtils::colorToMimeData( c ) );
308  drag->setPixmap( QgsColorWidget::createDragIcon( c ) );
309  drag->exec( Qt::CopyAction );
310  setDown( false );
311 }
312 
313 void QgsColorButton::mouseReleaseEvent( QMouseEvent *e )
314 {
315  if ( mPickingColor )
316  {
317  //end color picking operation by sampling the color under cursor
318  stopPicking( e->globalPos() );
319  e->accept();
320  return;
321  }
322 
323  QToolButton::mouseReleaseEvent( e );
324 }
325 
326 void QgsColorButton::stopPicking( QPoint eventPos, bool samplingColor )
327 {
328  //release mouse and keyboard, and reset cursor
329  releaseMouse();
330  releaseKeyboard();
331  QgsApplication::restoreOverrideCursor();
332  setMouseTracking( false );
333  mPickingColor = false;
334 
335  if ( !samplingColor )
336  {
337  //not sampling color, restore old color
339  return;
340  }
341 
342  setColor( QgsGui::sampleColor( eventPos ) );
343  addRecentColor( mColor );
344 }
345 
346 QColor QgsColorButton::linkedProjectColor() const
347 {
348  QList<QgsProjectColorScheme *> projectSchemes;
349  QgsApplication::colorSchemeRegistry()->schemes( projectSchemes );
350  if ( projectSchemes.length() > 0 )
351  {
352  QgsProjectColorScheme *scheme = projectSchemes.at( 0 );
353  const QgsNamedColorList colors = scheme->fetchColors();
354  for ( const auto &color : colors )
355  {
356  if ( color.second.isEmpty() )
357  continue;
358 
359  if ( color.second == mLinkedColorName )
360  {
361  return color.first;
362  }
363  }
364  }
365  return QColor();
366 }
367 
368 void QgsColorButton::keyPressEvent( QKeyEvent *e )
369 {
370  if ( !mPickingColor )
371  {
372  //if not picking a color, use default tool button behavior
373  QToolButton::keyPressEvent( e );
374  return;
375  }
376 
377  //cancel picking, sampling the color if space was pressed
378  stopPicking( QCursor::pos(), e->key() == Qt::Key_Space );
379 }
380 
381 void QgsColorButton::dragEnterEvent( QDragEnterEvent *e )
382 {
383  const bool isProjectColor = linkedProjectColor().isValid();
384  if ( isProjectColor )
385  return;
386 
387  //is dragged data valid color data?
388  QColor mimeColor;
389  if ( colorFromMimeData( e->mimeData(), mimeColor ) )
390  {
391  //if so, we accept the drag, and temporarily change the button's color
392  //to match the dragged color. This gives immediate feedback to the user
393  //that colors can be dropped here
394  e->acceptProposedAction();
395  setButtonBackground( mimeColor );
396  }
397 }
398 
399 void QgsColorButton::dragLeaveEvent( QDragLeaveEvent *e )
400 {
401  Q_UNUSED( e )
402  //reset button color
404 }
405 
406 void QgsColorButton::dropEvent( QDropEvent *e )
407 {
408  const bool isProjectColor = linkedProjectColor().isValid();
409  if ( isProjectColor )
410  return;
411 
412  //is dropped data valid color data?
413  QColor mimeColor;
414  if ( colorFromMimeData( e->mimeData(), mimeColor ) )
415  {
416  //accept drop and set new color
417  e->acceptProposedAction();
418  setColor( mimeColor );
419  addRecentColor( mimeColor );
420  }
421 }
422 
423 void QgsColorButton::wheelEvent( QWheelEvent *event )
424 {
425  if ( mAllowOpacity && isEnabled() && !isNull() )
426  {
427  const double increment = ( ( event->modifiers() & Qt::ControlModifier ) ? 0.01 : 0.1 ) *
428  ( event->angleDelta().y() > 0 ? 1 : -1 );
429  const double alpha = std::min( std::max( 0.0, mColor.alphaF() + increment ), 1.0 );
430  mColor.setAlphaF( alpha );
431 
433  emit colorChanged( mColor );
434  event->accept();
435  }
436  else
437  {
438  QToolButton::wheelEvent( event );
439  }
440 }
441 
442 void QgsColorButton::setValidColor( const QColor &newColor )
443 {
444  if ( newColor.isValid() )
445  {
446  setColor( newColor );
447  addRecentColor( newColor );
448  }
449 }
450 
451 void QgsColorButton::setValidTemporaryColor( const QColor &newColor )
452 {
453  if ( newColor.isValid() )
454  {
455  setColor( newColor );
456  }
457 }
458 
459 QPixmap QgsColorButton::createMenuIcon( const QColor &color, const bool showChecks )
460 {
461  const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
462 
463  //create an icon pixmap
464  QPixmap pixmap( iconSize, iconSize );
465  pixmap.fill( Qt::transparent );
466 
467  QPainter p;
468  p.begin( &pixmap );
469 
470  //start with checkboard pattern
471  if ( showChecks )
472  {
473  const QBrush checkBrush = QBrush( transparentBackground() );
474  p.setPen( Qt::NoPen );
475  p.setBrush( checkBrush );
476  p.drawRect( 0, 0, iconSize - 1, iconSize - 1 );
477  }
478 
479  //draw color over pattern
480  p.setBrush( QBrush( color ) );
481 
482  //draw border
483  p.setPen( QColor( 197, 197, 197 ) );
484  p.drawRect( 0, 0, iconSize - 1, iconSize - 1 );
485  p.end();
486  return pixmap;
487 }
488 
489 void QgsColorButton::buttonClicked()
490 {
491  if ( linkedProjectColor().isValid() )
492  {
493  QToolButton::showMenu();
494  }
495  else
496  {
497  switch ( mBehavior )
498  {
499  case ShowDialog:
500  showColorDialog();
501  return;
502  case SignalOnly:
503  emit colorClicked( mColor );
504  return;
505  }
506  }
507 }
508 
509 void QgsColorButton::prepareMenu()
510 {
511  //we need to tear down and rebuild this menu every time it is shown. Otherwise the space allocated to any
512  //QgsColorSwatchGridAction is not recalculated by Qt and the swatch grid may not be the correct size
513  //for the number of colors shown in the grid. Note that we MUST refresh color swatch grids every time this
514  //menu is opened, otherwise color schemes like the recent color scheme grid are meaningless
515  mMenu->clear();
516 
517  const bool isProjectColor = linkedProjectColor().isValid();
518 
519  if ( !isProjectColor )
520  {
521  if ( mShowNull )
522  {
523  QAction *nullAction = new QAction( mNullColorString.isEmpty() ? tr( "Clear Color" ) : mNullColorString, this );
524  nullAction->setIcon( createMenuIcon( Qt::transparent, false ) );
525  mMenu->addAction( nullAction );
526  connect( nullAction, &QAction::triggered, this, &QgsColorButton::setToNull );
527  }
528 
529  //show default color option if set
530  if ( mDefaultColor.isValid() )
531  {
532  QAction *defaultColorAction = new QAction( tr( "Default Color" ), this );
533  defaultColorAction->setIcon( createMenuIcon( mDefaultColor ) );
534  mMenu->addAction( defaultColorAction );
535  connect( defaultColorAction, &QAction::triggered, this, &QgsColorButton::setToDefaultColor );
536  }
537 
538  if ( mShowNoColorOption )
539  {
540  QAction *noColorAction = new QAction( mNoColorString, this );
541  noColorAction->setIcon( createMenuIcon( Qt::transparent, false ) );
542  mMenu->addAction( noColorAction );
543  connect( noColorAction, &QAction::triggered, this, &QgsColorButton::setToNoColor );
544  }
545 
546  mMenu->addSeparator();
547  QgsColorWheel *colorWheel = new QgsColorWheel( mMenu );
548  colorWheel->setColor( color() );
549  QgsColorWidgetAction *colorAction = new QgsColorWidgetAction( colorWheel, mMenu, mMenu );
550  colorAction->setDismissOnColorSelection( false );
551  connect( colorAction, &QgsColorWidgetAction::colorChanged, this, &QgsColorButton::setColor );
552  mMenu->addAction( colorAction );
553  if ( mAllowOpacity )
554  {
556  alphaRamp->setColor( color() );
557  QgsColorWidgetAction *alphaAction = new QgsColorWidgetAction( alphaRamp, mMenu, mMenu );
558  alphaAction->setDismissOnColorSelection( false );
559  connect( alphaAction, &QgsColorWidgetAction::colorChanged, this, &QgsColorButton::setColor );
560  connect( alphaAction, &QgsColorWidgetAction::colorChanged, colorWheel, [colorWheel]( const QColor & color ) { colorWheel->setColor( color, false ); }
561  );
562  connect( colorAction, &QgsColorWidgetAction::colorChanged, alphaRamp, [alphaRamp]( const QColor & color ) { alphaRamp->setColor( color, false ); }
563  );
564  mMenu->addAction( alphaAction );
565  }
566 
567  if ( mColorSchemeRegistry )
568  {
569  //get schemes with ShowInColorButtonMenu flag set
570  QList< QgsColorScheme * > schemeList = mColorSchemeRegistry->schemes( QgsColorScheme::ShowInColorButtonMenu );
571  QList< QgsColorScheme * >::iterator it = schemeList.begin();
572  for ( ; it != schemeList.end(); ++it )
573  {
574  QgsColorSwatchGridAction *colorAction = new QgsColorSwatchGridAction( *it, mMenu, mContext, this );
575  colorAction->setBaseColor( mColor );
576  mMenu->addAction( colorAction );
577  connect( colorAction, &QgsColorSwatchGridAction::colorChanged, this, &QgsColorButton::setValidColor );
578  connect( colorAction, &QgsColorSwatchGridAction::colorChanged, this, &QgsColorButton::addRecentColor );
579  }
580  }
581 
582  mMenu->addSeparator();
583  }
584 
585  if ( isProjectColor )
586  {
587  QAction *unlinkAction = new QAction( tr( "Unlink Color" ), mMenu );
588  mMenu->addAction( unlinkAction );
589  connect( unlinkAction, &QAction::triggered, this, &QgsColorButton::unlink );
590  }
591 
592  QAction *copyColorAction = new QAction( tr( "Copy Color" ), this );
593  mMenu->addAction( copyColorAction );
594  connect( copyColorAction, &QAction::triggered, this, &QgsColorButton::copyColor );
595 
596  if ( !isProjectColor )
597  {
598  QAction *pasteColorAction = new QAction( tr( "Paste Color" ), this );
599  //enable or disable paste action based on current clipboard contents. We always show the paste
600  //action, even if it's disabled, to give hint to the user that pasting colors is possible
601  QColor clipColor;
602  if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor ) )
603  {
604  pasteColorAction->setIcon( createMenuIcon( clipColor ) );
605  }
606  else
607  {
608  pasteColorAction->setEnabled( false );
609  }
610  mMenu->addAction( pasteColorAction );
611  connect( pasteColorAction, &QAction::triggered, this, &QgsColorButton::pasteColor );
612 
613  QAction *pickColorAction = new QAction( tr( "Pick Color" ), this );
614  mMenu->addAction( pickColorAction );
615  connect( pickColorAction, &QAction::triggered, this, &QgsColorButton::activatePicker );
616 
617  QAction *chooseColorAction = new QAction( tr( "Choose Color…" ), this );
618  mMenu->addAction( chooseColorAction );
619  connect( chooseColorAction, &QAction::triggered, this, &QgsColorButton::showColorDialog );
620  }
621 }
622 
624 {
625  if ( e->type() == QEvent::EnabledChange )
626  {
628  }
629  QToolButton::changeEvent( e );
630 }
631 
632 #if 0 // causes too many cyclical updates, but may be needed on some platforms
633 void QgsColorButton::paintEvent( QPaintEvent *e )
634 {
635  QToolButton::paintEvent( e );
636 
637  if ( !mBackgroundSet )
638  {
640  }
641 }
642 #endif
643 
644 void QgsColorButton::showEvent( QShowEvent *e )
645 {
647  QToolButton::showEvent( e );
648 }
649 
650 void QgsColorButton::resizeEvent( QResizeEvent *event )
651 {
652  QToolButton::resizeEvent( event );
653  //recalculate icon size and redraw icon
654  mIconSize = QSize();
656 }
657 
658 void QgsColorButton::setColor( const QColor &color )
659 {
660  const QColor oldColor = mColor;
661  mColor = color;
662 
663  // handle when initially set color is same as default (Qt::black); consider it a color change
664  if ( oldColor != mColor || ( mColor == QColor( Qt::black ) && !mColorSet ) )
665  {
667  if ( isEnabled() )
668  {
669  // TODO: May be beneficial to have the option to set color without emitting this signal.
670  // Now done by blockSignals( bool ) where button is used
671  emit colorChanged( mColor );
672  }
673  }
674  mColorSet = true;
675 }
676 
677 void QgsColorButton::addRecentColor( const QColor &color )
678 {
680 }
681 
682 void QgsColorButton::setButtonBackground( const QColor &color )
683 {
684  QColor backgroundColor = color;
685  bool isProjectColor = false;
686  if ( !backgroundColor.isValid() && !mLinkedColorName.isEmpty() )
687  {
688  backgroundColor = linkedProjectColor();
689  isProjectColor = backgroundColor.isValid();
690  if ( !isProjectColor )
691  {
692  mLinkedColorName.clear(); //color has been deleted, renamed, etc...
693  emit unlinked();
694  }
695  }
696  if ( !backgroundColor.isValid() )
697  {
698  backgroundColor = mColor;
699  }
700 
701  QSize currentIconSize;
702  //icon size is button size with a small margin
703  if ( menu() )
704  {
705  if ( !mIconSize.isValid() )
706  {
707  //calculate size of push button part of widget (ie, without the menu drop-down button part)
708  QStyleOptionToolButton opt;
709  initStyleOption( &opt );
710  const QRect buttonSize = QApplication::style()->subControlRect( QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton,
711  this );
712  //make sure height of icon looks good under different platforms
713 #ifdef Q_OS_WIN
714  mIconSize = QSize( buttonSize.width() - 10, height() - 6 );
715 #else
716  mIconSize = QSize( buttonSize.width() - 10, height() - 12 );
717 #endif
718  }
719  currentIconSize = mIconSize;
720  }
721  else
722  {
723  //no menu
724 #ifdef Q_OS_WIN
725  currentIconSize = QSize( width() - 10, height() - 6 );
726 #else
727  currentIconSize = QSize( width() - 10, height() - 12 );
728 #endif
729  }
730 
731  if ( !currentIconSize.isValid() || currentIconSize.width() <= 0 || currentIconSize.height() <= 0 )
732  {
733  return;
734  }
735 
736  //create an icon pixmap
737  QPixmap pixmap( currentIconSize );
738  pixmap.fill( Qt::transparent );
739 
740  if ( backgroundColor.isValid() )
741  {
742  const QRect rect( 0, 0, currentIconSize.width(), currentIconSize.height() );
743  QPainter p;
744  p.begin( &pixmap );
745  p.setRenderHint( QPainter::Antialiasing );
746  p.setPen( Qt::NoPen );
747  if ( mAllowOpacity && backgroundColor.alpha() < 255 )
748  {
749  //start with checkboard pattern
750  const QBrush checkBrush = QBrush( transparentBackground() );
751  p.setBrush( checkBrush );
752  p.drawRoundedRect( rect, 3, 3 );
753  }
754 
755  //draw semi-transparent color on top
756  p.setBrush( backgroundColor );
757  p.drawRoundedRect( rect, 3, 3 );
758  p.end();
759  }
760 
761  setIconSize( currentIconSize );
762  setIcon( pixmap );
763 }
764 
766 {
767  //copy color
768  QColor c = linkedProjectColor();
769  if ( !c.isValid() )
770  c = mColor;
771  QApplication::clipboard()->setMimeData( QgsSymbolLayerUtils::colorToMimeData( c ) );
772 }
773 
775 {
776  QColor clipColor;
777  if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor ) )
778  {
779  //paste color
780  setColor( clipColor );
781  addRecentColor( clipColor );
782  }
783 }
784 
786 {
787  //activate picker color
788  // Store current color
789  mCurrentColor = mColor;
790  QApplication::setOverrideCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::Sampler ) );
791  grabMouse();
792  grabKeyboard();
793  mPickingColor = true;
794  setMouseTracking( true );
795 }
796 
797 QColor QgsColorButton::color() const
798 {
799  QColor c = linkedProjectColor();
800  if ( !c.isValid() )
801  c = mColor;
802  return c;
803 }
804 
805 void QgsColorButton::setAllowOpacity( const bool allow )
806 {
807  mAllowOpacity = allow;
808 }
809 
810 void QgsColorButton::setColorDialogTitle( const QString &title )
811 {
812  mColorDialogTitle = title;
813 }
814 
816 {
817  return mColorDialogTitle;
818 }
819 
820 void QgsColorButton::setShowMenu( const bool showMenu )
821 {
822  mShowMenu = showMenu;
823  setMenu( showMenu ? mMenu : nullptr );
824  setPopupMode( showMenu ? QToolButton::MenuButtonPopup : QToolButton::DelayedPopup );
825  //force recalculation of icon size
826  mIconSize = QSize();
828 }
829 
831 {
832  mBehavior = behavior;
833 }
834 
835 void QgsColorButton::setDefaultColor( const QColor &color )
836 {
837  mDefaultColor = color;
838 }
839 
840 void QgsColorButton::setShowNull( bool showNull, const QString &nullString )
841 {
842  mShowNull = showNull;
843  mNullColorString = nullString;
844 }
845 
847 {
848  return mShowNull;
849 }
850 
852 {
853  return !mColor.isValid();
854 }
855 
856 void QgsColorButton::linkToProjectColor( const QString &name )
857 {
858  mLinkedColorName = name;
860 }
861 
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:1856
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.
Behavior behavior
void setDefaultColor(const QColor &color)
Sets the default color for the button, which is shown in the button's drop-down menu for the "default...
void mouseReleaseEvent(QMouseEvent *e) override
Reimplemented to allow color picking.
void dragLeaveEvent(QDragLeaveEvent *e) override
Reimplemented to reset button appearance after drag leave.
void colorChanged(const QColor &color)
Emitted whenever a new color is set for the button.
void copyColor()
Copies the current color to the clipboard.
void setButtonBackground(const QColor &color=QColor())
Sets the background pixmap for the button based upon color and transparency.
void mousePressEvent(QMouseEvent *e) override
Reimplemented to detect right mouse button clicks on the color button and allow dragging colors.
bool event(QEvent *e) override
void dropEvent(QDropEvent *e) override
Reimplemented to accept dropped colors.
static const QPixmap & transparentBackground()
Returns a checkboard pattern pixmap for use as a background to transparent colors.
Behavior
Specifies the behavior when the button is clicked.
@ ShowDialog
Show a color picker dialog when clicked.
@ SignalOnly
Emit colorClicked signal only, no dialog.
void setShowMenu(bool showMenu)
Sets whether the drop-down menu should be shown for the button.
QgsColorButton(QWidget *parent=nullptr, const QString &cdt=QString(), QgsColorSchemeRegistry *registry=nullptr)
Construct a new color ramp button.
QSize sizeHint() const override
static QPixmap createMenuIcon(const QColor &color, bool showChecks=true)
Creates an icon for displaying a color in a drop-down menu.
void setBehavior(Behavior behavior)
Sets the behavior for when the button is clicked.
void setColorDialogTitle(const QString &title)
Set the title for the color chooser dialog window.
QSize minimumSizeHint() const override
void setShowNull(bool showNull, const QString &nullString=QString())
Sets whether a set to null (clear) option is shown in the button's drop-down menu.
void linkToProjectColor(const QString &name)
Sets the button to link to an existing project color, by color name.
void unlinked()
Emitted when the color is unlinked, e.g.
void setAllowOpacity(bool allowOpacity)
Sets whether opacity modification (transparency) is permitted for the color.
void setToNoColor()
Sets color to a totally transparent color.
void activatePicker()
Activates the color picker tool, which allows for sampling a color from anywhere on the screen.
void mouseMoveEvent(QMouseEvent *e) override
Reimplemented to allow dragging colors from button.
void showEvent(QShowEvent *e) override
void setToDefaultColor()
Sets color to the button's default color, if set.
void colorClicked(const QColor &color)
Emitted when the button is clicked, if the button's behavior is set to SignalOnly.
void cleared()
Emitted when the color is cleared (set to null).
QString colorDialogTitle
void dragEnterEvent(QDragEnterEvent *e) override
Reimplemented to accept dragged colors.
void unlink()
Unlinks the button from a project color.
void setToNull()
Sets color to null.
void wheelEvent(QWheelEvent *event) override
bool isNull() const
Returns true if the current color is null.
void keyPressEvent(QKeyEvent *e) override
Reimplemented to allow canceling color pick via keypress, and sample via space bar press.
void resizeEvent(QResizeEvent *event) override
bool showNull() const
Returns whether the set to null (clear) option is shown in the button's drop-down menu.
void pasteColor()
Pastes a color from the clipboard to the color button.
void setColor(const QColor &color)
Sets the current color for the button.
void changeEvent(QEvent *e) override
A custom QGIS dialog for selecting a color.
A color ramp widget.
@ Horizontal
Horizontal ramp.
Registry of color schemes.
QList< QgsColorScheme * > schemes() const
Returns all color schemes in the registry.
@ ShowInColorButtonMenu
Show scheme in color button drop-down menu.
A color swatch grid which can be embedded into a 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.
A color wheel widget.
void setColor(const QColor &color, bool emitSignals=false) override
An action containing a color widget, which can be embedded into a menu.
void setDismissOnColorSelection(bool dismiss)
Sets whether the parent menu should be dismissed and closed when a color is selected from the action'...
void colorChanged(const QColor &color)
Emitted when a color has been selected from the widget.
static QPixmap createDragIcon(const QColor &color)
Create an icon for dragging colors.
virtual void setColor(const QColor &color, bool emitSignals=false)
Sets the color for the widget.
@ Alpha
Alpha component (opacity) of color.
A custom QGIS widget for selecting a color, including options for selecting colors via hue wheel,...
@ LayoutVertical
Use a narrower, vertically stacked layout.
void currentColorChanged(const QColor &color)
Emitted when the dialog's color changes.
void setPreviousColor(const QColor &color)
Sets the color to show in an optional "previous color" section.
void setAllowOpacity(bool allowOpacity)
Sets whether opacity modification (transparency) is permitted for the color dialog.
static QColor sampleColor(QPoint point)
Samples the color on screen at the specified global point (pixel).
Definition: qgsgui.cpp:237
Base class for any widget that can be shown as a inline panel.
void openPanel(QgsPanelWidget *panel)
Open a panel or dialog depending on dock mode setting If dock mode is true this method will emit the ...
static QgsPanelWidget * findParentPanel(QWidget *widget)
Traces through the parents of a widget to find if it is contained within a QgsPanelWidget widget.
void setPanelTitle(const QString &panelTitle)
Set the title of the panel when shown in the interface.
bool dockMode()
Returns the dock mode state.
A color scheme which contains project specific colors set through project properties dialog.
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.
Definition: qgsproject.cpp:479
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.
This class is a composition of two QSettings instances:
Definition: qgssettings.h:62
QVariant value(const QString &key, const QVariant &defaultValue=QVariant(), Section section=NoSection) const
Returns the value for setting key.
static QString encodeColor(const QColor &color)
static QColor colorFromMimeData(const QMimeData *data, bool &hasAlpha)
Attempts to parse mime data as a color.
static 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.
QSize iconSize(bool dockableToolbar)
Returns the user-preferred size of a window's toolbar icons.
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