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