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