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