QGIS API Documentation 3.30.0-'s-Hertogenbosch (f186b8efe0)
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"
20#include "qgsvectorlayer.h"
22#include "qgsstyle.h"
23#include "qgscolorwidgets.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
41QgsSymbolButton::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
59void 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
132void 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 {
152 newSymbol = QgsSymbol::defaultSymbol( Qgis::GeometryType::Point );
153 break;
155 newSymbol = QgsSymbol::defaultSymbol( Qgis::GeometryType::Line );
156 break;
158 newSymbol = QgsSymbol::defaultSymbol( Qgis::GeometryType::Polygon );
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
199void QgsSymbolButton::updateSymbolFromWidget()
200{
201 if ( QgsSymbolSelectorWidget *w = qobject_cast<QgsSymbolSelectorWidget *>( sender() ) )
202 setSymbol( w->symbol()->clone() );
203}
204
205void 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 mDefaultSymbol.reset( symbol );
252}
253
255{
256 return mDefaultSymbol.get();
257}
258
260{
261 mSymbol.reset( symbol );
262 updateSizeHint();
263 updatePreview();
264 emit changed();
265}
266
267void QgsSymbolButton::setColor( const QColor &color )
268{
269 if ( !mSymbol )
270 return;
271
272 QColor opaque = color;
273 opaque.setAlphaF( 1.0 );
274
275 if ( opaque == mSymbol->color() )
276 return;
277
278 mSymbol->setColor( opaque );
279 updatePreview();
280 emit changed();
281}
282
284{
285 QApplication::clipboard()->setMimeData( QgsSymbolLayerUtils::symbolToMimeData( mSymbol.get() ) );
286}
287
289{
290 std::unique_ptr< QgsSymbol > symbol( QgsSymbolLayerUtils::symbolFromMimeData( QApplication::clipboard()->mimeData() ) );
291 if ( symbol && symbol->type() == mType )
292 setSymbol( symbol.release() );
293}
294
296{
297 QApplication::clipboard()->setMimeData( QgsSymbolLayerUtils::colorToMimeData( mSymbol->color() ) );
298}
299
301{
302 QColor clipColor;
303 bool hasAlpha = false;
304 if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor, hasAlpha ) )
305 {
306 //paste color
307 setColor( clipColor );
309 }
310}
311
313{
314 if ( mPickingColor )
315 {
316 //don't show dialog if in color picker mode
317 e->accept();
318 return;
319 }
320
321 if ( e->button() == Qt::RightButton )
322 {
323 QToolButton::showMenu();
324 return;
325 }
326 else if ( e->button() == Qt::LeftButton )
327 {
328 mDragStartPosition = e->pos();
329 }
330 QToolButton::mousePressEvent( e );
331}
332
334{
335 if ( mPickingColor )
336 {
337 updatePreview( QgsGui::sampleColor( e->globalPos() ) );
338 e->accept();
339 return;
340 }
341
342 //handle dragging colors/symbols from button
343
344 if ( !( e->buttons() & Qt::LeftButton ) )
345 {
346 //left button not depressed, so not a drag
347 QToolButton::mouseMoveEvent( e );
348 return;
349 }
350
351 if ( ( e->pos() - mDragStartPosition ).manhattanLength() < QApplication::startDragDistance() )
352 {
353 //mouse not moved, so not a drag
354 QToolButton::mouseMoveEvent( e );
355 return;
356 }
357
358 //user is dragging
359 QDrag *drag = new QDrag( this );
360 drag->setMimeData( QgsSymbolLayerUtils::colorToMimeData( mSymbol->color() ) );
361 drag->setPixmap( QgsColorWidget::createDragIcon( mSymbol->color() ) );
362 drag->exec( Qt::CopyAction );
363 setDown( false );
364}
365
367{
368 if ( mPickingColor )
369 {
370 //end color picking operation by sampling the color under cursor
371 stopPicking( e->globalPos() );
372 e->accept();
373 return;
374 }
375
376 QToolButton::mouseReleaseEvent( e );
377}
378
380{
381 if ( !mPickingColor )
382 {
383 //if not picking a color, use default tool button behavior
384 QToolButton::keyPressEvent( e );
385 return;
386 }
387
388 //cancel picking, sampling the color if space was pressed
389 stopPicking( QCursor::pos(), e->key() == Qt::Key_Space );
390}
391
392void QgsSymbolButton::dragEnterEvent( QDragEnterEvent *e )
393{
394 //is dragged data valid color data?
395 QColor mimeColor;
396 bool hasAlpha = false;
397
398 if ( colorFromMimeData( e->mimeData(), mimeColor, hasAlpha ) )
399 {
400 //if so, we accept the drag, and temporarily change the button's color
401 //to match the dragged color. This gives immediate feedback to the user
402 //that colors can be dropped here
403 e->acceptProposedAction();
404 updatePreview( mimeColor );
405 }
406}
407
408void QgsSymbolButton::dragLeaveEvent( QDragLeaveEvent *e )
409{
410 Q_UNUSED( e )
411 //reset button color
412 updatePreview();
413}
414
415void QgsSymbolButton::dropEvent( QDropEvent *e )
416{
417 //is dropped data valid format data?
418 QColor mimeColor;
419 bool hasAlpha = false;
420 if ( colorFromMimeData( e->mimeData(), mimeColor, hasAlpha ) )
421 {
422 //accept drop and set new color
423 e->acceptProposedAction();
424 mimeColor.setAlphaF( 1.0 );
425 mSymbol->setColor( mimeColor );
427 updatePreview();
428 emit changed();
429 }
430 updatePreview();
431}
432
433void QgsSymbolButton::wheelEvent( QWheelEvent *event )
434{
435 if ( isEnabled() && mSymbol )
436 {
437 bool symbolChanged = false;
438 const double increment = ( ( event->modifiers() & Qt::ControlModifier ) ? 0.1 : 1 ) *
439 ( event->angleDelta().y() > 0 ? 1 : -1 );
440 switch ( mSymbol->type() )
441 {
443 {
444 QgsMarkerSymbol *marker = qgis::down_cast<QgsMarkerSymbol *>( mSymbol.get() );
445 if ( marker )
446 {
447 const double size = std::max( 0.0, marker->size() + increment );
448 marker->setSize( size );
449 symbolChanged = true;
450 }
451 break;
452 }
453
455 {
456 QgsLineSymbol *line = qgis::down_cast<QgsLineSymbol *>( mSymbol.get() );
457 if ( line )
458 {
459 const double width = std::max( 0.0, line->width() + increment );
460 line->setWidth( width );
461 symbolChanged = true;
462 }
463 break;
464 }
465
468 break;
469 }
470
471 if ( symbolChanged )
472 {
473 updatePreview();
474 emit changed();
475 }
476
477 event->accept();
478 }
479 else
480 {
481 QToolButton::wheelEvent( event );
482 }
483}
484
485void QgsSymbolButton::prepareMenu()
486{
487 //we need to tear down and rebuild this menu every time it is shown. Otherwise the space allocated to any
488 //QgsColorSwatchGridAction is not recalculated by Qt and the swatch grid may not be the correct size
489 //for the number of colors shown in the grid. Note that we MUST refresh color swatch grids every time this
490 //menu is opened, otherwise color schemes like the recent color scheme grid are meaningless
491 mMenu->clear();
492
493 QAction *configureAction = new QAction( tr( "Configure Symbol…" ), this );
494 mMenu->addAction( configureAction );
495 connect( configureAction, &QAction::triggered, this, &QgsSymbolButton::showSettingsDialog );
496
497 QAction *copySymbolAction = new QAction( tr( "Copy Symbol" ), this );
498 copySymbolAction->setEnabled( !isNull() );
499 mMenu->addAction( copySymbolAction );
500 connect( copySymbolAction, &QAction::triggered, this, &QgsSymbolButton::copySymbol );
501
502 const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
503
504 QAction *pasteSymbolAction = new QAction( tr( "Paste Symbol" ), this );
505 //enable or disable paste action based on current clipboard contents. We always show the paste
506 //action, even if it's disabled, to give hint to the user that pasting symbols is possible
507 std::unique_ptr< QgsSymbol > tempSymbol( QgsSymbolLayerUtils::symbolFromMimeData( QApplication::clipboard()->mimeData() ) );
508 if ( tempSymbol && tempSymbol->type() == mType )
509 {
510 pasteSymbolAction->setIcon( QgsSymbolLayerUtils::symbolPreviewIcon( tempSymbol.get(), QSize( iconSize, iconSize ), 1 ) );
511 }
512 else
513 {
514 pasteSymbolAction->setEnabled( false );
515 }
516 mMenu->addAction( pasteSymbolAction );
517 connect( pasteSymbolAction, &QAction::triggered, this, &QgsSymbolButton::pasteSymbol );
518
519 if ( mShowNull )
520 {
521 QAction *nullAction = new QAction( tr( "Clear Current Symbol" ), this );
522 nullAction->setEnabled( !isNull() );
523 mMenu->addAction( nullAction );
524 connect( nullAction, &QAction::triggered, this, &QgsSymbolButton::setToNull );
525 }
526
527 //show default symbol option if set
528 if ( mDefaultSymbol )
529 {
530 QAction *defaultSymbolAction = new QAction( tr( "Default Symbol" ), this );
531 defaultSymbolAction->setIcon( QgsSymbolLayerUtils::symbolPreviewIcon( mDefaultSymbol.get(), QSize( iconSize, iconSize ), 1 ) );
532 mMenu->addAction( defaultSymbolAction );
533 connect( defaultSymbolAction, &QAction::triggered, this, &QgsSymbolButton::setToDefaultSymbol );
534 }
535
536 if ( mSymbol )
537 {
538 mMenu->addSeparator();
539
540 QgsColorWheel *colorWheel = new QgsColorWheel( mMenu );
541 colorWheel->setColor( mSymbol->color() );
542 QgsColorWidgetAction *colorAction = new QgsColorWidgetAction( colorWheel, mMenu, mMenu );
543 colorAction->setDismissOnColorSelection( false );
544 connect( colorAction, &QgsColorWidgetAction::colorChanged, this, &QgsSymbolButton::setColor );
545 mMenu->addAction( colorAction );
546
548 QColor alphaColor = mSymbol->color();
549 alphaColor.setAlphaF( mSymbol->opacity() );
550 alphaRamp->setColor( alphaColor );
551 QgsColorWidgetAction *alphaAction = new QgsColorWidgetAction( alphaRamp, mMenu, mMenu );
552 alphaAction->setDismissOnColorSelection( false );
553 connect( alphaAction, &QgsColorWidgetAction::colorChanged, this, [ = ]( const QColor & color )
554 {
555 const double opacity = color.alphaF();
556 mSymbol->setOpacity( opacity );
557 updatePreview();
558 emit changed();
559 } );
560 connect( colorAction, &QgsColorWidgetAction::colorChanged, alphaRamp, [alphaRamp]( const QColor & color ) { alphaRamp->setColor( color, false ); }
561 );
562 mMenu->addAction( alphaAction );
563
564 //get schemes with ShowInColorButtonMenu flag set
565 QList< QgsColorScheme * > schemeList = QgsApplication::colorSchemeRegistry()->schemes( QgsColorScheme::ShowInColorButtonMenu );
566 QList< QgsColorScheme * >::iterator it = schemeList.begin();
567 for ( ; it != schemeList.end(); ++it )
568 {
569 QgsColorSwatchGridAction *colorAction = new QgsColorSwatchGridAction( *it, mMenu, QStringLiteral( "symbology" ), this );
570 colorAction->setBaseColor( mSymbol->color() );
571 mMenu->addAction( colorAction );
573 connect( colorAction, &QgsColorSwatchGridAction::colorChanged, this, &QgsSymbolButton::addRecentColor );
574 }
575
576 mMenu->addSeparator();
577
578 QAction *copyColorAction = new QAction( tr( "Copy Color" ), this );
579 mMenu->addAction( copyColorAction );
580 connect( copyColorAction, &QAction::triggered, this, &QgsSymbolButton::copyColor );
581
582 QAction *pasteColorAction = new QAction( tr( "Paste Color" ), this );
583 //enable or disable paste action based on current clipboard contents. We always show the paste
584 //action, even if it's disabled, to give hint to the user that pasting colors is possible
585 QColor clipColor;
586 bool hasAlpha = false;
587 if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor, hasAlpha ) )
588 {
589 pasteColorAction->setIcon( createColorIcon( clipColor ) );
590 }
591 else
592 {
593 pasteColorAction->setEnabled( false );
594 }
595 mMenu->addAction( pasteColorAction );
596 connect( pasteColorAction, &QAction::triggered, this, &QgsSymbolButton::pasteColor );
597
598 QAction *pickColorAction = new QAction( tr( "Pick Color" ), this );
599 mMenu->addAction( pickColorAction );
600 connect( pickColorAction, &QAction::triggered, this, &QgsSymbolButton::activatePicker );
601
602 QAction *chooseColorAction = new QAction( tr( "Choose Color…" ), this );
603 mMenu->addAction( chooseColorAction );
604 connect( chooseColorAction, &QAction::triggered, this, &QgsSymbolButton::showColorDialog );
605 }
606}
607
608void QgsSymbolButton::addRecentColor( const QColor &color )
609{
611}
612
613void QgsSymbolButton::activatePicker()
614{
615 //activate picker color
616 QApplication::setOverrideCursor( QgsApplication::getThemeCursor( QgsApplication::Cursor::Sampler ) );
617 grabMouse();
618 grabKeyboard();
619 mPickingColor = true;
620 setMouseTracking( true );
621}
622
623
625{
626 if ( e->type() == QEvent::EnabledChange )
627 {
628 updatePreview();
629 }
630 QToolButton::changeEvent( e );
631}
632
633void QgsSymbolButton::showEvent( QShowEvent *e )
634{
635 updatePreview();
636 QToolButton::showEvent( e );
637}
638
639void QgsSymbolButton::resizeEvent( QResizeEvent *event )
640{
641 QToolButton::resizeEvent( event );
642 //recalculate icon size and redraw icon
643 mIconSize = QSize();
644 updatePreview();
645}
646
647void QgsSymbolButton::updatePreview( const QColor &color, QgsSymbol *tempSymbol )
648{
649 QSize currentIconSize;
650 //icon size is button size with a small margin
651 if ( menu() )
652 {
653 if ( !mIconSize.isValid() )
654 {
655 //calculate size of push button part of widget (ie, without the menu dropdown button part)
656 QStyleOptionToolButton opt;
657 initStyleOption( &opt );
658 const QRect buttonSize = QApplication::style()->subControlRect( QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton,
659 this );
660 //make sure height of icon looks good under different platforms
661#ifdef Q_OS_WIN
662 mIconSize = QSize( buttonSize.width() - 10, height() - 6 );
663#else
664 mIconSize = QSize( buttonSize.width() - 10, height() - 12 );
665#endif
666 }
667 currentIconSize = mIconSize;
668 }
669 else
670 {
671 //no menu
672#ifdef Q_OS_WIN
673 currentIconSize = QSize( width() - 10, height() - 6 );
674#else
675 currentIconSize = QSize( width() - 10, height() - 12 );
676#endif
677 }
678
679 if ( !currentIconSize.isValid() || currentIconSize.width() <= 0 || currentIconSize.height() <= 0 )
680 {
681 return;
682 }
683
684 std::unique_ptr< QgsSymbol > previewSymbol;
685
686 if ( tempSymbol )
687 {
688 previewSymbol.reset( tempSymbol->clone() );
689 }
690 else if ( mSymbol )
691 {
692 previewSymbol.reset( mSymbol->clone() );
693 }
694 else
695 {
696 setIconSize( currentIconSize );
697 setIcon( QIcon() );
698 setToolTip( QString( ) );
699 return;
700 }
701
702 if ( color.isValid() )
703 previewSymbol->setColor( color );
704
705 //create an icon pixmap
706 const QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( previewSymbol.get(), currentIconSize );
707 setIconSize( currentIconSize );
708 setIcon( icon );
709
710 // set tooltip
711 // create very large preview image
712 const int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 23 );
713 const int height = static_cast< int >( width / 1.61803398875 ); // golden ratio
714
715 const QPixmap pm = QgsSymbolLayerUtils::symbolPreviewPixmap( previewSymbol.get(), QSize( width, height ), height / 20 );
716 QByteArray data;
717 QBuffer buffer( &data );
718 pm.save( &buffer, "PNG", 100 );
719 setToolTip( QStringLiteral( "<img src='data:image/png;base64, %3'>" ).arg( QString( data.toBase64() ) ) );
720}
721
722bool QgsSymbolButton::colorFromMimeData( const QMimeData *mimeData, QColor &resultColor, bool &hasAlpha )
723{
724 hasAlpha = false;
725 const QColor mimeColor = QgsSymbolLayerUtils::colorFromMimeData( mimeData, hasAlpha );
726
727 if ( mimeColor.isValid() )
728 {
729 resultColor = mimeColor;
730 return true;
731 }
732
733 //could not get color from mime data
734 return false;
735}
736
737QPixmap QgsSymbolButton::createColorIcon( const QColor &color ) const
738{
739 //create an icon pixmap
740 const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
741 QPixmap pixmap( iconSize, iconSize );
742 pixmap.fill( Qt::transparent );
743
744 QPainter p;
745 p.begin( &pixmap );
746
747 //draw color over pattern
748 p.setBrush( QBrush( color ) );
749
750 //draw border
751 p.setPen( QColor( 197, 197, 197 ) );
752 p.drawRect( 0, 0, iconSize - 1, iconSize - 1 );
753 p.end();
754 return pixmap;
755}
756
757void QgsSymbolButton::stopPicking( QPoint eventPos, bool samplingColor )
758{
759 //release mouse and keyboard, and reset cursor
760 releaseMouse();
761 releaseKeyboard();
762 QgsApplication::restoreOverrideCursor();
763 setMouseTracking( false );
764 mPickingColor = false;
765
766 if ( !samplingColor )
767 {
768 //not sampling color, restore old icon
769 updatePreview();
770 return;
771 }
772
773 const QColor newColor = QgsGui::sampleColor( eventPos );
774 setColor( newColor );
775 addRecentColor( newColor );
776}
777
778void QgsSymbolButton::showColorDialog()
779{
780 if ( !mSymbol )
781 return;
782
784 if ( panel && panel->dockMode() )
785 {
786 const QColor currentColor = mSymbol->color();
788 colorWidget->setPanelTitle( tr( "Symbol Color" ) );
789 colorWidget->setAllowOpacity( true );
790
791 if ( currentColor.isValid() )
792 {
793 colorWidget->setPreviousColor( currentColor );
794 }
795
796 connect( colorWidget, &QgsCompoundColorWidget::currentColorChanged, this, [ = ]( const QColor & newColor )
797 {
798 if ( newColor.isValid() )
799 {
800 setColor( newColor );
801 }
802 } );
803 panel->openPanel( colorWidget );
804 return;
805 }
806
807 QgsColorDialog dialog( this, Qt::WindowFlags(), mSymbol->color() );
808 dialog.setTitle( tr( "Symbol Color" ) );
809 dialog.setAllowOpacity( true );
810
811 if ( dialog.exec() && dialog.color().isValid() )
812 {
813 setColor( dialog.color() );
814 }
815
816 // reactivate button's window
817 activateWindow();
818}
819
820void QgsSymbolButton::setDialogTitle( const QString &title )
821{
822 mDialogTitle = title;
823}
824
826{
827 return mDialogTitle;
828}
829
831{
832 return mSymbol.get();
833}
834
835void QgsSymbolButton::setShowNull( bool showNull )
836{
837 mShowNull = showNull;
838}
839
841{
842 return mShowNull;
843}
844
846{
847 return !mSymbol;
848}
849
851{
852 setSymbol( nullptr );
853}
854
856{
857 if ( !mDefaultSymbol )
858 {
859 return;
860 }
861
862 setSymbol( mDefaultSymbol->clone() );
863}
SymbolType
Symbol types.
Definition: qgis.h:320
@ Marker
Marker symbol.
@ Line
Line symbol.
@ Fill
Fill symbol.
@ Hybrid
Hybrid symbol.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:3278
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 setDefaultSymbol(QgsSymbol *symbol)
Sets the default symbol for the button, which is shown in the button's drop-down menu for the "defaul...
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 setToDefaultSymbol()
Sets symbol to the button's default symbol, if set.
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.
const QgsSymbol * defaultSymbol() const
Returns the default symbol for the button, which is shown in the button's drop-down menu for the "def...
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.
void setContext(const QgsSymbolWidgetContext &context)
Sets the context in which the symbol widget is shown, e.g., the associated map canvas and expression ...
QgsSymbol * symbol()
Returns the symbol that is currently active in the widget.
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
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
Qgis::SymbolType type() const
Returns the symbol's type.
Definition: qgssymbol.h:152
static QgsSymbol * defaultSymbol(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Definition: qgssymbol.cpp:704
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,...