QGIS API Documentation  3.27.0-Master (11ef3e5184)
qgssymbolbutton.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  qgssymbolbutton.h
3  -----------------
4  Date : July 2017
5  Copyright : (C) 2017 by Nyall Dawson
6  Email : nyall dot dawson at gmail dot com
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 "qgssymbolbutton.h"
17 #include "qgspanelwidget.h"
18 #include "qgsexpressioncontext.h"
20 #include "qgsvectorlayer.h"
22 #include "qgsstyle.h"
23 #include "qgscolorwidgets.h"
24 #include "qgscolorschemeregistry.h"
25 #include "qgscolorswatchgrid.h"
26 #include "qgssymbollayerutils.h"
27 #include "qgsapplication.h"
28 #include "qgsguiutils.h"
30 #include "qgsgui.h"
31 #include "qgscolordialog.h"
32 #include "qgsfillsymbol.h"
33 #include "qgslinesymbol.h"
34 #include "qgsmarkersymbol.h"
35 
36 #include <QMenu>
37 #include <QClipboard>
38 #include <QDrag>
39 #include <QBuffer>
40 
41 QgsSymbolButton::QgsSymbolButton( QWidget *parent, const QString &dialogTitle )
42  : QToolButton( parent )
43  , mDialogTitle( dialogTitle.isEmpty() ? tr( "Symbol Settings" ) : dialogTitle )
44 {
45  mSymbol.reset( QgsFillSymbol::createSimple( QVariantMap() ) );
46 
47  setAcceptDrops( true );
48  connect( this, &QAbstractButton::clicked, this, &QgsSymbolButton::showSettingsDialog );
49 
50  //setup dropdown menu
51  mMenu = new QMenu( this );
52  connect( mMenu, &QMenu::aboutToShow, this, &QgsSymbolButton::prepareMenu );
53  setMenu( mMenu );
54  setPopupMode( QToolButton::MenuButtonPopup );
55 
56  updateSizeHint();
57 }
58 
59 void QgsSymbolButton::updateSizeHint()
60 {
61  //make sure height of button looks good under different platforms
62  const QSize size = QToolButton::minimumSizeHint();
63  const int fontHeight = static_cast< int >( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 1.4 );
64  switch ( mType )
65  {
67  if ( mSymbol )
68  {
69  mSizeHint = QSize( size.width(), std::max( size.height(), fontHeight * 3 ) );
70  setMaximumWidth( mSizeHint.height() * 1.5 );
71  setMinimumWidth( maximumWidth() );
72  }
73  else
74  {
75  mSizeHint = QSize( size.width(), fontHeight );
76  setMaximumWidth( 999999 );
77  mSizeHint.setWidth( QToolButton::sizeHint().width() );
78  }
79  break;
80 
84  mSizeHint = QSize( size.width(), std::max( size.height(), fontHeight ) );
85  break;
86  }
87 
88  setMinimumHeight( mSizeHint.height( ) );
89 
90  updateGeometry();
91 }
92 
94 
96 {
97  return mSizeHint;
98 }
99 
101 {
102  return mSizeHint;
103 }
104 
106 {
107  if ( type != mType )
108  {
109  switch ( type )
110  {
112  mSymbol.reset( QgsMarkerSymbol::createSimple( QVariantMap() ) );
113  break;
114 
116  mSymbol.reset( QgsLineSymbol::createSimple( QVariantMap() ) );
117  break;
118 
120  mSymbol.reset( QgsFillSymbol::createSimple( QVariantMap() ) );
121  break;
122 
124  break;
125  }
126  }
127  mType = type;
128  updateSizeHint();
129  updatePreview();
130 }
131 
132 void QgsSymbolButton::showSettingsDialog()
133 {
134  QgsExpressionContext context;
135  if ( mExpressionContextGenerator )
136  context = mExpressionContextGenerator->createExpressionContext();
137  else
138  {
140  }
141 
142  QgsSymbol *newSymbol = nullptr;
143  if ( mSymbol )
144  {
145  newSymbol = mSymbol->clone();
146  }
147  else
148  {
149  switch ( mType )
150  {
153  break;
156  break;
159  break;
161  break;
162  }
163  }
164 
165  QgsSymbolWidgetContext symbolContext;
166  symbolContext.setExpressionContext( &context );
167  symbolContext.setMapCanvas( mMapCanvas );
168  symbolContext.setMessageBar( mMessageBar );
169 
171  if ( panel && panel->dockMode() )
172  {
173  QgsSymbolSelectorWidget *d = new QgsSymbolSelectorWidget( newSymbol, QgsStyle::defaultStyle(), mLayer, panel );
174  d->setPanelTitle( mDialogTitle );
175  d->setContext( symbolContext );
176  connect( d, &QgsPanelWidget::widgetChanged, this, &QgsSymbolButton::updateSymbolFromWidget );
177  connect( d, &QgsPanelWidget::panelAccepted, this, &QgsSymbolButton::cleanUpSymbolSelector );
178  panel->openPanel( d );
179  }
180  else
181  {
182  QgsSymbolSelectorDialog dialog( newSymbol, QgsStyle::defaultStyle(), mLayer, this );
183  dialog.setWindowTitle( mDialogTitle );
184  dialog.setContext( symbolContext );
185  if ( dialog.exec() )
186  {
187  setSymbol( newSymbol );
188  }
189  else
190  {
191  delete newSymbol;
192  }
193 
194  // reactivate button's window
195  activateWindow();
196  }
197 }
198 
199 void QgsSymbolButton::updateSymbolFromWidget()
200 {
201  if ( QgsSymbolSelectorWidget *w = qobject_cast<QgsSymbolSelectorWidget *>( sender() ) )
202  setSymbol( w->symbol()->clone() );
203 }
204 
205 void QgsSymbolButton::cleanUpSymbolSelector( QgsPanelWidget *container )
206 {
207  QgsSymbolSelectorWidget *w = qobject_cast<QgsSymbolSelectorWidget *>( container );
208  if ( !w )
209  return;
210 
211  delete w->symbol();
212 }
213 
215 {
216  return mMapCanvas;
217 }
218 
220 {
221  mMapCanvas = mapCanvas;
222 }
223 
225 {
226  mMessageBar = bar;
227 }
228 
230 {
231  return mMessageBar;
232 }
233 
235 {
236  return mLayer;
237 }
238 
240 {
241  mLayer = layer;
242 }
243 
245 {
246  mExpressionContextGenerator = generator;
247 }
248 
250 {
251  mSymbol.reset( symbol );
252  updateSizeHint();
253  updatePreview();
254  emit changed();
255 }
256 
257 void QgsSymbolButton::setColor( const QColor &color )
258 {
259  if ( !mSymbol )
260  return;
261 
262  QColor opaque = color;
263  opaque.setAlphaF( 1.0 );
264 
265  if ( opaque == mSymbol->color() )
266  return;
267 
268  mSymbol->setColor( opaque );
269  updatePreview();
270  emit changed();
271 }
272 
274 {
275  QApplication::clipboard()->setMimeData( QgsSymbolLayerUtils::symbolToMimeData( mSymbol.get() ) );
276 }
277 
279 {
280  std::unique_ptr< QgsSymbol > symbol( QgsSymbolLayerUtils::symbolFromMimeData( QApplication::clipboard()->mimeData() ) );
281  if ( symbol && symbol->type() == mType )
282  setSymbol( symbol.release() );
283 }
284 
286 {
287  QApplication::clipboard()->setMimeData( QgsSymbolLayerUtils::colorToMimeData( mSymbol->color() ) );
288 }
289 
291 {
292  QColor clipColor;
293  bool hasAlpha = false;
294  if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor, hasAlpha ) )
295  {
296  //paste color
297  setColor( clipColor );
299  }
300 }
301 
302 void QgsSymbolButton::mousePressEvent( QMouseEvent *e )
303 {
304  if ( mPickingColor )
305  {
306  //don't show dialog if in color picker mode
307  e->accept();
308  return;
309  }
310 
311  if ( e->button() == Qt::RightButton )
312  {
313  QToolButton::showMenu();
314  return;
315  }
316  else if ( e->button() == Qt::LeftButton )
317  {
318  mDragStartPosition = e->pos();
319  }
320  QToolButton::mousePressEvent( e );
321 }
322 
323 void QgsSymbolButton::mouseMoveEvent( QMouseEvent *e )
324 {
325  if ( mPickingColor )
326  {
327  updatePreview( QgsGui::sampleColor( e->globalPos() ) );
328  e->accept();
329  return;
330  }
331 
332  //handle dragging colors/symbols from button
333 
334  if ( !( e->buttons() & Qt::LeftButton ) )
335  {
336  //left button not depressed, so not a drag
337  QToolButton::mouseMoveEvent( e );
338  return;
339  }
340 
341  if ( ( e->pos() - mDragStartPosition ).manhattanLength() < QApplication::startDragDistance() )
342  {
343  //mouse not moved, so not a drag
344  QToolButton::mouseMoveEvent( e );
345  return;
346  }
347 
348  //user is dragging
349  QDrag *drag = new QDrag( this );
350  drag->setMimeData( QgsSymbolLayerUtils::colorToMimeData( mSymbol->color() ) );
351  drag->setPixmap( QgsColorWidget::createDragIcon( mSymbol->color() ) );
352  drag->exec( Qt::CopyAction );
353  setDown( false );
354 }
355 
357 {
358  if ( mPickingColor )
359  {
360  //end color picking operation by sampling the color under cursor
361  stopPicking( e->globalPos() );
362  e->accept();
363  return;
364  }
365 
366  QToolButton::mouseReleaseEvent( e );
367 }
368 
369 void QgsSymbolButton::keyPressEvent( QKeyEvent *e )
370 {
371  if ( !mPickingColor )
372  {
373  //if not picking a color, use default tool button behavior
374  QToolButton::keyPressEvent( e );
375  return;
376  }
377 
378  //cancel picking, sampling the color if space was pressed
379  stopPicking( QCursor::pos(), e->key() == Qt::Key_Space );
380 }
381 
382 void QgsSymbolButton::dragEnterEvent( QDragEnterEvent *e )
383 {
384  //is dragged data valid color data?
385  QColor mimeColor;
386  bool hasAlpha = false;
387 
388  if ( colorFromMimeData( e->mimeData(), mimeColor, hasAlpha ) )
389  {
390  //if so, we accept the drag, and temporarily change the button's color
391  //to match the dragged color. This gives immediate feedback to the user
392  //that colors can be dropped here
393  e->acceptProposedAction();
394  updatePreview( mimeColor );
395  }
396 }
397 
398 void QgsSymbolButton::dragLeaveEvent( QDragLeaveEvent *e )
399 {
400  Q_UNUSED( e )
401  //reset button color
402  updatePreview();
403 }
404 
405 void QgsSymbolButton::dropEvent( QDropEvent *e )
406 {
407  //is dropped data valid format data?
408  QColor mimeColor;
409  bool hasAlpha = false;
410  if ( colorFromMimeData( e->mimeData(), mimeColor, hasAlpha ) )
411  {
412  //accept drop and set new color
413  e->acceptProposedAction();
414  mimeColor.setAlphaF( 1.0 );
415  mSymbol->setColor( mimeColor );
417  updatePreview();
418  emit changed();
419  }
420  updatePreview();
421 }
422 
423 void QgsSymbolButton::wheelEvent( QWheelEvent *event )
424 {
425  if ( isEnabled() && mSymbol )
426  {
427  bool symbolChanged = false;
428  const double increment = ( ( event->modifiers() & Qt::ControlModifier ) ? 0.1 : 1 ) *
429  ( event->angleDelta().y() > 0 ? 1 : -1 );
430  switch ( mSymbol->type() )
431  {
433  {
434  QgsMarkerSymbol *marker = qgis::down_cast<QgsMarkerSymbol *>( mSymbol.get() );
435  if ( marker )
436  {
437  const double size = std::max( 0.0, marker->size() + increment );
438  marker->setSize( size );
439  symbolChanged = true;
440  }
441  break;
442  }
443 
445  {
446  QgsLineSymbol *line = qgis::down_cast<QgsLineSymbol *>( mSymbol.get() );
447  if ( line )
448  {
449  const double width = std::max( 0.0, line->width() + increment );
450  line->setWidth( width );
451  symbolChanged = true;
452  }
453  break;
454  }
455 
458  break;
459  }
460 
461  if ( symbolChanged )
462  {
463  updatePreview();
464  emit changed();
465  }
466 
467  event->accept();
468  }
469  else
470  {
471  QToolButton::wheelEvent( event );
472  }
473 }
474 
475 void QgsSymbolButton::prepareMenu()
476 {
477  //we need to tear down and rebuild this menu every time it is shown. Otherwise the space allocated to any
478  //QgsColorSwatchGridAction is not recalculated by Qt and the swatch grid may not be the correct size
479  //for the number of colors shown in the grid. Note that we MUST refresh color swatch grids every time this
480  //menu is opened, otherwise color schemes like the recent color scheme grid are meaningless
481  mMenu->clear();
482 
483  QAction *configureAction = new QAction( tr( "Configure Symbol…" ), this );
484  mMenu->addAction( configureAction );
485  connect( configureAction, &QAction::triggered, this, &QgsSymbolButton::showSettingsDialog );
486 
487  QAction *copySymbolAction = new QAction( tr( "Copy Symbol" ), this );
488  copySymbolAction->setEnabled( !isNull() );
489  mMenu->addAction( copySymbolAction );
490  connect( copySymbolAction, &QAction::triggered, this, &QgsSymbolButton::copySymbol );
491 
492  QAction *pasteSymbolAction = new QAction( tr( "Paste Symbol" ), this );
493  //enable or disable paste action based on current clipboard contents. We always show the paste
494  //action, even if it's disabled, to give hint to the user that pasting symbols is possible
495  std::unique_ptr< QgsSymbol > tempSymbol( QgsSymbolLayerUtils::symbolFromMimeData( QApplication::clipboard()->mimeData() ) );
496  if ( tempSymbol && tempSymbol->type() == mType )
497  {
498  const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
499  pasteSymbolAction->setIcon( QgsSymbolLayerUtils::symbolPreviewIcon( tempSymbol.get(), QSize( iconSize, iconSize ), 1 ) );
500  }
501  else
502  {
503  pasteSymbolAction->setEnabled( false );
504  }
505  mMenu->addAction( pasteSymbolAction );
506  connect( pasteSymbolAction, &QAction::triggered, this, &QgsSymbolButton::pasteSymbol );
507 
508  if ( mShowNull )
509  {
510  QAction *nullAction = new QAction( tr( "Clear Current Symbol" ), this );
511  nullAction->setEnabled( !isNull() );
512  mMenu->addAction( nullAction );
513  connect( nullAction, &QAction::triggered, this, &QgsSymbolButton::setToNull );
514  }
515 
516  if ( mSymbol )
517  {
518  mMenu->addSeparator();
519 
520  QgsColorWheel *colorWheel = new QgsColorWheel( mMenu );
521  colorWheel->setColor( mSymbol->color() );
522  QgsColorWidgetAction *colorAction = new QgsColorWidgetAction( colorWheel, mMenu, mMenu );
523  colorAction->setDismissOnColorSelection( false );
524  connect( colorAction, &QgsColorWidgetAction::colorChanged, this, &QgsSymbolButton::setColor );
525  mMenu->addAction( colorAction );
526 
528  QColor alphaColor = mSymbol->color();
529  alphaColor.setAlphaF( mSymbol->opacity() );
530  alphaRamp->setColor( alphaColor );
531  QgsColorWidgetAction *alphaAction = new QgsColorWidgetAction( alphaRamp, mMenu, mMenu );
532  alphaAction->setDismissOnColorSelection( false );
533  connect( alphaAction, &QgsColorWidgetAction::colorChanged, this, [ = ]( const QColor & color )
534  {
535  const double opacity = color.alphaF();
536  mSymbol->setOpacity( opacity );
537  updatePreview();
538  emit changed();
539  } );
540  connect( colorAction, &QgsColorWidgetAction::colorChanged, alphaRamp, [alphaRamp]( const QColor & color ) { alphaRamp->setColor( color, false ); }
541  );
542  mMenu->addAction( alphaAction );
543 
544  //get schemes with ShowInColorButtonMenu flag set
545  QList< QgsColorScheme * > schemeList = QgsApplication::colorSchemeRegistry()->schemes( QgsColorScheme::ShowInColorButtonMenu );
546  QList< QgsColorScheme * >::iterator it = schemeList.begin();
547  for ( ; it != schemeList.end(); ++it )
548  {
549  QgsColorSwatchGridAction *colorAction = new QgsColorSwatchGridAction( *it, mMenu, QStringLiteral( "symbology" ), this );
550  colorAction->setBaseColor( mSymbol->color() );
551  mMenu->addAction( colorAction );
552  connect( colorAction, &QgsColorSwatchGridAction::colorChanged, this, &QgsSymbolButton::setColor );
553  connect( colorAction, &QgsColorSwatchGridAction::colorChanged, this, &QgsSymbolButton::addRecentColor );
554  }
555 
556  mMenu->addSeparator();
557 
558  QAction *copyColorAction = new QAction( tr( "Copy Color" ), this );
559  mMenu->addAction( copyColorAction );
560  connect( copyColorAction, &QAction::triggered, this, &QgsSymbolButton::copyColor );
561 
562  QAction *pasteColorAction = new QAction( tr( "Paste Color" ), this );
563  //enable or disable paste action based on current clipboard contents. We always show the paste
564  //action, even if it's disabled, to give hint to the user that pasting colors is possible
565  QColor clipColor;
566  bool hasAlpha = false;
567  if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor, hasAlpha ) )
568  {
569  pasteColorAction->setIcon( createColorIcon( clipColor ) );
570  }
571  else
572  {
573  pasteColorAction->setEnabled( false );
574  }
575  mMenu->addAction( pasteColorAction );
576  connect( pasteColorAction, &QAction::triggered, this, &QgsSymbolButton::pasteColor );
577 
578  QAction *pickColorAction = new QAction( tr( "Pick Color" ), this );
579  mMenu->addAction( pickColorAction );
580  connect( pickColorAction, &QAction::triggered, this, &QgsSymbolButton::activatePicker );
581 
582  QAction *chooseColorAction = new QAction( tr( "Choose Color…" ), this );
583  mMenu->addAction( chooseColorAction );
584  connect( chooseColorAction, &QAction::triggered, this, &QgsSymbolButton::showColorDialog );
585  }
586 }
587 
588 void QgsSymbolButton::addRecentColor( const QColor &color )
589 {
591 }
592 
593 void QgsSymbolButton::activatePicker()
594 {
595  //activate picker color
596  QApplication::setOverrideCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::Sampler ) );
597  grabMouse();
598  grabKeyboard();
599  mPickingColor = true;
600  setMouseTracking( true );
601 }
602 
603 
605 {
606  if ( e->type() == QEvent::EnabledChange )
607  {
608  updatePreview();
609  }
610  QToolButton::changeEvent( e );
611 }
612 
613 void QgsSymbolButton::showEvent( QShowEvent *e )
614 {
615  updatePreview();
616  QToolButton::showEvent( e );
617 }
618 
619 void QgsSymbolButton::resizeEvent( QResizeEvent *event )
620 {
621  QToolButton::resizeEvent( event );
622  //recalculate icon size and redraw icon
623  mIconSize = QSize();
624  updatePreview();
625 }
626 
627 void QgsSymbolButton::updatePreview( const QColor &color, QgsSymbol *tempSymbol )
628 {
629  QSize currentIconSize;
630  //icon size is button size with a small margin
631  if ( menu() )
632  {
633  if ( !mIconSize.isValid() )
634  {
635  //calculate size of push button part of widget (ie, without the menu dropdown button part)
636  QStyleOptionToolButton opt;
637  initStyleOption( &opt );
638  const QRect buttonSize = QApplication::style()->subControlRect( QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton,
639  this );
640  //make sure height of icon looks good under different platforms
641 #ifdef Q_OS_WIN
642  mIconSize = QSize( buttonSize.width() - 10, height() - 6 );
643 #else
644  mIconSize = QSize( buttonSize.width() - 10, height() - 12 );
645 #endif
646  }
647  currentIconSize = mIconSize;
648  }
649  else
650  {
651  //no menu
652 #ifdef Q_OS_WIN
653  currentIconSize = QSize( width() - 10, height() - 6 );
654 #else
655  currentIconSize = QSize( width() - 10, height() - 12 );
656 #endif
657  }
658 
659  if ( !currentIconSize.isValid() || currentIconSize.width() <= 0 || currentIconSize.height() <= 0 )
660  {
661  return;
662  }
663 
664  std::unique_ptr< QgsSymbol > previewSymbol;
665 
666  if ( tempSymbol )
667  {
668  previewSymbol.reset( tempSymbol->clone() );
669  }
670  else if ( mSymbol )
671  {
672  previewSymbol.reset( mSymbol->clone() );
673  }
674  else
675  {
676  setIconSize( currentIconSize );
677  setIcon( QIcon() );
678  setToolTip( QString( ) );
679  return;
680  }
681 
682  if ( color.isValid() )
683  previewSymbol->setColor( color );
684 
685  //create an icon pixmap
686  const QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( previewSymbol.get(), currentIconSize );
687  setIconSize( currentIconSize );
688  setIcon( icon );
689 
690  // set tooltip
691  // create very large preview image
692  const int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 23 );
693  const int height = static_cast< int >( width / 1.61803398875 ); // golden ratio
694 
695  const QPixmap pm = QgsSymbolLayerUtils::symbolPreviewPixmap( previewSymbol.get(), QSize( width, height ), height / 20 );
696  QByteArray data;
697  QBuffer buffer( &data );
698  pm.save( &buffer, "PNG", 100 );
699  setToolTip( QStringLiteral( "<img src='data:image/png;base64, %3'>" ).arg( QString( data.toBase64() ) ) );
700 }
701 
702 bool QgsSymbolButton::colorFromMimeData( const QMimeData *mimeData, QColor &resultColor, bool &hasAlpha )
703 {
704  hasAlpha = false;
705  const QColor mimeColor = QgsSymbolLayerUtils::colorFromMimeData( mimeData, hasAlpha );
706 
707  if ( mimeColor.isValid() )
708  {
709  resultColor = mimeColor;
710  return true;
711  }
712 
713  //could not get color from mime data
714  return false;
715 }
716 
717 QPixmap QgsSymbolButton::createColorIcon( const QColor &color ) const
718 {
719  //create an icon pixmap
720  const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
721  QPixmap pixmap( iconSize, iconSize );
722  pixmap.fill( Qt::transparent );
723 
724  QPainter p;
725  p.begin( &pixmap );
726 
727  //draw color over pattern
728  p.setBrush( QBrush( color ) );
729 
730  //draw border
731  p.setPen( QColor( 197, 197, 197 ) );
732  p.drawRect( 0, 0, iconSize - 1, iconSize - 1 );
733  p.end();
734  return pixmap;
735 }
736 
737 void QgsSymbolButton::stopPicking( QPoint eventPos, bool samplingColor )
738 {
739  //release mouse and keyboard, and reset cursor
740  releaseMouse();
741  releaseKeyboard();
742  QgsApplication::restoreOverrideCursor();
743  setMouseTracking( false );
744  mPickingColor = false;
745 
746  if ( !samplingColor )
747  {
748  //not sampling color, restore old icon
749  updatePreview();
750  return;
751  }
752 
753  const QColor newColor = QgsGui::sampleColor( eventPos );
754  setColor( newColor );
755  addRecentColor( newColor );
756 }
757 
758 void QgsSymbolButton::showColorDialog()
759 {
760  if ( !mSymbol )
761  return;
762 
764  if ( panel && panel->dockMode() )
765  {
766  const QColor currentColor = mSymbol->color();
768  colorWidget->setPanelTitle( tr( "Symbol Color" ) );
769  colorWidget->setAllowOpacity( true );
770 
771  if ( currentColor.isValid() )
772  {
773  colorWidget->setPreviousColor( currentColor );
774  }
775 
776  connect( colorWidget, &QgsCompoundColorWidget::currentColorChanged, this, [ = ]( const QColor & newColor )
777  {
778  if ( newColor.isValid() )
779  {
780  setColor( newColor );
781  }
782  } );
783  panel->openPanel( colorWidget );
784  return;
785  }
786 
787  QgsColorDialog dialog( this, Qt::WindowFlags(), mSymbol->color() );
788  dialog.setTitle( tr( "Symbol Color" ) );
789  dialog.setAllowOpacity( true );
790 
791  if ( dialog.exec() && dialog.color().isValid() )
792  {
793  setColor( dialog.color() );
794  }
795 
796  // reactivate button's window
797  activateWindow();
798 }
799 
800 void QgsSymbolButton::setDialogTitle( const QString &title )
801 {
802  mDialogTitle = title;
803 }
804 
806 {
807  return mDialogTitle;
808 }
809 
811 {
812  return mSymbol.get();
813 }
814 
815 void QgsSymbolButton::setShowNull( bool showNull )
816 {
817  mShowNull = showNull;
818 }
819 
821 {
822  return mShowNull;
823 }
824 
826 {
827  return !mSymbol;
828 }
829 
831 {
832  setSymbol( nullptr );
833 }
SymbolType
Symbol types.
Definition: qgis.h:206
@ Marker
Marker symbol.
@ Line
Line symbol.
@ Fill
Fill symbol.
@ Hybrid
Hybrid symbol.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:2304
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.
A custom QGIS dialog for selecting a color.
A color ramp widget.
@ Horizontal
Horizontal ramp.
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.
Abstract interface for generating an expression context.
virtual QgsExpressionContext createExpressionContext() const =0
This method needs to be reimplemented in all classes which implement this interface and return an exp...
static QList< QgsExpressionContextScope * > globalProjectLayerScopes(const QgsMapLayer *layer)
Creates a list of three scopes: global, layer's project and layer.
Expression contexts are used to encapsulate the parameters around which a QgsExpression should be eva...
void appendScopes(const QList< QgsExpressionContextScope * > &scopes)
Appends a list of scopes to the end of the context.
static QgsFillSymbol * createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
static QColor sampleColor(QPoint point)
Samples the color on screen at the specified global point (pixel).
Definition: qgsgui.cpp:235
A line symbol type, for rendering LineString and MultiLineString geometries.
Definition: qgslinesymbol.h:30
void setWidth(double width) const
Sets the width for the whole line symbol.
double width() const
Returns the estimated width for the whole symbol, which is the maximum width of all marker symbol lay...
static QgsLineSymbol * createSimple(const QVariantMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties.
Map canvas is a class for displaying all GIS data types on a canvas.
Definition: qgsmapcanvas.h:90
A marker symbol type, for rendering Point and MultiPoint geometries.
void setSize(double size) const
Sets the size for the whole symbol.
static QgsMarkerSymbol * createSimple(const QVariantMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
double size() const
Returns the estimated size for the whole symbol, which is the maximum size of all marker symbol layer...
A bar for displaying non-blocking messages to the user.
Definition: qgsmessagebar.h:61
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 ...
void panelAccepted(QgsPanelWidget *panel)
Emitted when the panel is accepted by the user.
void widgetChanged()
Emitted when the widget state changes.
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.
static void addRecentColor(const QColor &color)
Adds a color to the list of recent colors.
static QgsStyle * defaultStyle()
Returns default application-wide style.
Definition: qgsstyle.cpp:145
void wheelEvent(QWheelEvent *event) override
void mouseReleaseEvent(QMouseEvent *e) override
QSize sizeHint() const override
void changeEvent(QEvent *e) override
void setColor(const QColor &color)
Sets the current color for the symbol.
void copySymbol()
Copies the current symbol to the clipboard.
QgsSymbolButton(QWidget *parent=nullptr, const QString &dialogTitle=QString())
Construct a new symbol button.
void copyColor()
Copies the current symbol color to the clipboard.
void setMessageBar(QgsMessageBar *bar)
Sets the message bar associated with the widget.
void pasteSymbol()
Pastes a symbol from the clipboard.
void setSymbol(QgsSymbol *symbol)
Sets the symbol for the button.
void mousePressEvent(QMouseEvent *e) override
void dragEnterEvent(QDragEnterEvent *e) override
void showEvent(QShowEvent *e) override
void setSymbolType(Qgis::SymbolType type)
Sets the symbol type which the button requires.
void setDialogTitle(const QString &title)
Sets the title for the symbol settings dialog window.
void keyPressEvent(QKeyEvent *e) override
void setLayer(QgsVectorLayer *layer)
Sets a layer to associate with the widget.
void resizeEvent(QResizeEvent *event) override
void registerExpressionContextGenerator(QgsExpressionContextGenerator *generator)
Register an expression context generator class that will be used to retrieve an expression context fo...
QSize minimumSizeHint() const override
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
void setMapCanvas(QgsMapCanvas *canvas)
Sets a map canvas to associate with the widget.
void dropEvent(QDropEvent *e) override
void pasteColor()
Pastes a color from the clipboard to the symbol.
void changed()
Emitted when the symbol's settings are changed.
void dragLeaveEvent(QDragLeaveEvent *e) override
void setToNull()
Sets symbol to to null.
void setShowNull(bool showNull)
Sets whether a set to null (clear) option is shown in the button's drop-down menu.
QgsVectorLayer * layer() const
Returns the layer associated with the widget.
QgsSymbol * symbol()
Returns the current symbol defined by the button.
QgsMapCanvas * mapCanvas() const
Returns the map canvas associated with the widget.
void mouseMoveEvent(QMouseEvent *e) override
bool isNull() const
Returns true if the current symbol is null.
bool showNull() const
Returns whether the set to null (clear) option is shown in the button's drop-down menu.
static QgsSymbol * symbolFromMimeData(const QMimeData *data)
Attempts to parse mime data as a symbol.
static QPixmap symbolPreviewPixmap(const QgsSymbol *symbol, QSize size, int padding=0, QgsRenderContext *customContext=nullptr, bool selected=false, const QgsExpressionContext *expressionContext=nullptr, const QgsLegendPatchShape *shape=nullptr)
Returns a pixmap preview for a color ramp.
static QMimeData * symbolToMimeData(const QgsSymbol *symbol)
Creates new mime data from a symbol.
static QColor colorFromMimeData(const QMimeData *data, bool &hasAlpha)
Attempts to parse mime data as a color.
static QIcon symbolPreviewIcon(const QgsSymbol *symbol, QSize size, int padding=0, QgsLegendPatchShape *shape=nullptr)
Returns an icon preview for a color ramp.
static QMimeData * colorToMimeData(const QColor &color)
Creates mime data from a color.
Symbol selector widget that can be used to select and build a symbol.
QgsSymbol * symbol()
Returns the symbol that is currently active in the widget.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
Contains settings which reflect the context in which a symbol (or renderer) widget is shown,...
void setMapCanvas(QgsMapCanvas *canvas)
Sets the map canvas associated with the widget.
void setMessageBar(QgsMessageBar *bar)
Sets the message bar associated with the widget.
void setExpressionContext(QgsExpressionContext *context)
Sets the optional expression context used for the widget.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:93
static QgsSymbol * defaultSymbol(QgsWkbTypes::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:673
Qgis::SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:152
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
Represents a vector layer which manages a vector based data sets.
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,...