44#include "moc_qgssymbolbutton.cpp"
46using namespace Qt::StringLiterals;
49 : QToolButton( parent )
54 setAcceptDrops(
true );
55 connect(
this, &QAbstractButton::clicked,
this, &QgsSymbolButton::showSettingsDialog );
58 mMenu =
new QMenu(
this );
59 connect( mMenu, &QMenu::aboutToShow,
this, &QgsSymbolButton::prepareMenu );
61 setPopupMode( QToolButton::MenuButtonPopup );
66void QgsSymbolButton::updateSizeHint()
69 const QSize size = QToolButton::minimumSizeHint();
74 if ( mFixedSizeConstraints )
78 mSizeHint = QSize( size.width(), std::max( size.height(), fontHeight * 3 ) );
79 setMaximumWidth( mSizeHint.height() * 1.5 );
80 setMinimumWidth( maximumWidth() );
84 mSizeHint = QSize( size.width(), fontHeight );
85 setMaximumWidth( 999999 );
86 mSizeHint.setWidth( QToolButton::sizeHint().width() );
91 setMaximumWidth( 999999 );
92 mSizeHint = QSize( size.width(), std::max( size.height(), fontHeight ) );
99 mSizeHint = QSize( size.width(), std::max( size.height(), fontHeight ) );
103 setMinimumHeight( mSizeHint.height() );
147void QgsSymbolButton::showSettingsDialog()
150 if ( mExpressionContextGenerator )
157 std::unique_ptr<QgsSymbol> newSymbol;
160 newSymbol.reset( mSymbol->clone() );
180 QgsSymbolWidgetContext symbolContext;
197 dialog.setWindowTitle( mDialogTitle );
198 dialog.setContext( symbolContext );
246 mExpressionContextGenerator = generator;
251 mDefaultSymbol.reset(
symbol );
256 return mDefaultSymbol.get();
272 QColor opaque = color;
273 opaque.setAlphaF( 1.0 );
275 if ( opaque == mSymbol->color() )
278 mSymbol->setColor( opaque );
303 bool hasAlpha =
false;
304 if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor, hasAlpha ) )
321 if ( e->button() == Qt::RightButton )
323 QToolButton::showMenu();
326 else if ( e->button() == Qt::LeftButton )
328 mDragStartPosition = e->pos();
330 QToolButton::mousePressEvent( e );
344 if ( !( e->buttons() & Qt::LeftButton ) )
347 QToolButton::mouseMoveEvent( e );
351 if ( ( e->pos() - mDragStartPosition ).manhattanLength() < QApplication::startDragDistance() )
354 QToolButton::mouseMoveEvent( e );
359 QDrag *drag =
new QDrag(
this );
362 drag->exec( Qt::CopyAction );
371 stopPicking( e->globalPos() );
376 QToolButton::mouseReleaseEvent( e );
381 if ( !mPickingColor )
384 QToolButton::keyPressEvent( e );
389 stopPicking( QCursor::pos(), e->key() == Qt::Key_Space );
396 bool hasAlpha =
false;
398 if ( colorFromMimeData( e->mimeData(), mimeColor, hasAlpha ) )
403 e->acceptProposedAction();
404 updatePreview( mimeColor );
419 bool hasAlpha =
false;
420 if ( colorFromMimeData( e->mimeData(), mimeColor, hasAlpha ) )
423 e->acceptProposedAction();
424 mimeColor.setAlphaF( 1.0 );
425 mSymbol->setColor( mimeColor );
435 if ( isEnabled() && mSymbol )
437 bool symbolChanged =
false;
438 const double increment = ( (
event->modifiers() & Qt::ControlModifier ) ? 0.1 : 1 ) * (
event->angleDelta().y() > 0 ? 1 : -1 );
439 switch ( mSymbol->type() )
443 QgsMarkerSymbol *marker = qgis::down_cast<QgsMarkerSymbol *>( mSymbol.get() );
446 const double size = std::max( 0.0, marker->
size() + increment );
448 symbolChanged =
true;
455 QgsLineSymbol *line = qgis::down_cast<QgsLineSymbol *>( mSymbol.get() );
458 const double width = std::max( 0.0, line->
width() + increment );
460 symbolChanged =
true;
480 QToolButton::wheelEvent( event );
484void QgsSymbolButton::prepareMenu()
492 QAction *configureAction =
new QAction( tr(
"Configure Symbol…" ),
this );
493 mMenu->addAction( configureAction );
494 connect( configureAction, &QAction::triggered,
this, &QgsSymbolButton::showSettingsDialog );
496 QAction *copySymbolAction =
new QAction( tr(
"Copy Symbol" ),
this );
497 copySymbolAction->setEnabled( !
isNull() );
498 mMenu->addAction( copySymbolAction );
503 QAction *pasteSymbolAction =
new QAction( tr(
"Paste Symbol" ),
this );
507 if ( tempSymbol && tempSymbol->type() == mType )
513 pasteSymbolAction->setEnabled(
false );
515 mMenu->addAction( pasteSymbolAction );
520 QAction *nullAction =
new QAction( tr(
"Clear Current Symbol" ),
this );
521 nullAction->setEnabled( !
isNull() );
522 mMenu->addAction( nullAction );
527 if ( mDefaultSymbol )
529 QAction *defaultSymbolAction =
new QAction( tr(
"Default Symbol" ),
this );
531 mMenu->addAction( defaultSymbolAction );
537 mMenu->addSeparator();
539 QgsColorWheel *colorWheel =
new QgsColorWheel( mMenu );
540 colorWheel->
setColor( mSymbol->color() );
541 QgsColorWidgetAction *colorAction =
new QgsColorWidgetAction( colorWheel, mMenu, mMenu );
544 mMenu->addAction( colorAction );
547 QColor alphaColor = mSymbol->color();
548 alphaColor.setAlphaF( mSymbol->opacity() );
550 QgsColorWidgetAction *alphaAction =
new QgsColorWidgetAction( alphaRamp, mMenu, mMenu );
553 const double opacity = color.alphaF();
554 mSymbol->setOpacity( opacity );
559 mMenu->addAction( alphaAction );
563 QList<QgsColorScheme *>::iterator it = schemeList.begin();
564 for ( ; it != schemeList.end(); ++it )
566 QgsColorSwatchGridAction *colorAction =
new QgsColorSwatchGridAction( *it, mMenu, u
"symbology"_s,
this );
568 mMenu->addAction( colorAction );
573 mMenu->addSeparator();
575 QAction *copyColorAction =
new QAction( tr(
"Copy Color" ),
this );
576 mMenu->addAction( copyColorAction );
579 QAction *pasteColorAction =
new QAction( tr(
"Paste Color" ),
this );
583 bool hasAlpha =
false;
584 if ( colorFromMimeData( QApplication::clipboard()->mimeData(), clipColor, hasAlpha ) )
586 pasteColorAction->setIcon( createColorIcon( clipColor ) );
590 pasteColorAction->setEnabled(
false );
592 mMenu->addAction( pasteColorAction );
595 QAction *pickColorAction =
new QAction( tr(
"Pick Color" ),
this );
596 mMenu->addAction( pickColorAction );
597 connect( pickColorAction, &QAction::triggered,
this, &QgsSymbolButton::activatePicker );
599 QAction *chooseColorAction =
new QAction( tr(
"Choose Color…" ),
this );
600 mMenu->addAction( chooseColorAction );
601 connect( chooseColorAction, &QAction::triggered,
this, &QgsSymbolButton::showColorDialog );
605void QgsSymbolButton::addRecentColor(
const QColor &color )
610void QgsSymbolButton::activatePicker()
616 mPickingColor =
true;
617 setMouseTracking(
true );
623 if ( e->type() == QEvent::EnabledChange )
627 QToolButton::changeEvent( e );
633 QToolButton::showEvent( e );
638 QToolButton::resizeEvent( event );
644void QgsSymbolButton::updatePreview(
const QColor &color,
QgsSymbol *tempSymbol )
646 QSize currentIconSize;
650 if ( !mIconSize.isValid() )
653 QStyleOptionToolButton opt;
654 initStyleOption( &opt );
655 const QRect buttonSize = QApplication::style()->subControlRect( QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton,
this );
658 mIconSize = QSize( buttonSize.width() - 10, height() - 6 );
660 mIconSize = QSize( buttonSize.width() - 10, height() - 12 );
663 currentIconSize = mIconSize;
669 currentIconSize = QSize( width() - 10, height() - 6 );
671 currentIconSize = QSize( width() - 10, height() - 12 );
675 if ( !currentIconSize.isValid() || currentIconSize.width() <= 0 || currentIconSize.height() <= 0 )
680 std::unique_ptr<QgsSymbol> previewSymbol;
684 previewSymbol.reset( tempSymbol->
clone() );
688 previewSymbol.reset( mSymbol->clone() );
692 setIconSize( currentIconSize );
694 setToolTip( QString() );
698 if ( color.isValid() )
699 previewSymbol->setColor( color );
703 setIconSize( currentIconSize );
708 const int width =
static_cast<int>(
Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance(
'X' ) * 23 );
709 const int height =
static_cast<int>( width / 1.61803398875 );
713 QBuffer buffer( &data );
714 pm.save( &buffer,
"PNG", 100 );
715 setToolTip( u
"<img src='data:image/png;base64, %3' width=\"%4\">"_s.arg( QString( data.toBase64() ) ).arg( width ) );
718bool QgsSymbolButton::colorFromMimeData(
const QMimeData *mimeData, QColor &resultColor,
bool &hasAlpha )
723 if ( mimeColor.isValid() )
725 resultColor = mimeColor;
733QPixmap QgsSymbolButton::createColorIcon(
const QColor &color )
const
737 QPixmap pixmap( iconSize, iconSize );
738 pixmap.fill( Qt::transparent );
744 p.setBrush( QBrush( color ) );
747 p.setPen( QColor( 197, 197, 197 ) );
748 p.drawRect( 0, 0, iconSize - 1, iconSize - 1 );
753void QgsSymbolButton::stopPicking( QPoint eventPos,
bool samplingColor )
758 QgsApplication::restoreOverrideCursor();
759 setMouseTracking(
false );
760 mPickingColor =
false;
762 if ( !samplingColor )
771 addRecentColor( newColor );
774void QgsSymbolButton::showColorDialog()
782 const QColor currentColor = mSymbol->color();
787 if ( currentColor.isValid() )
793 if ( newColor.isValid() )
802 QgsColorDialog dialog(
this, Qt::WindowFlags(), mSymbol->color() );
803 dialog.setTitle( tr(
"Symbol Color" ) );
804 dialog.setAllowOpacity(
true );
806 if ( dialog.exec() && dialog.color().isValid() )
817 mDialogTitle = title;
827 return mSymbol.get();
849 return mFixedSizeConstraints;
864 if ( !mDefaultSymbol )
static const double UI_SCALE_FACTOR
UI scaling factor.
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.
@ Sampler
Color/Value picker.
QList< QgsColorScheme * > schemes() const
Returns all color schemes in the registry.
@ ShowInColorButtonMenu
Show scheme in color button drop-down 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.
void setColor(const QColor &color, bool emitSignals=false) override
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 std::unique_ptr< 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).
A line symbol type, for rendering LineString and MultiLineString geometries.
void setWidth(double width) const
Sets the width for the whole line symbol.
static std::unique_ptr< QgsLineSymbol > createSimple(const QVariantMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties.
double width() const
Returns the estimated width for the whole symbol, which is the maximum width of all marker symbol lay...
Map canvas is a class for displaying all GIS data types on a canvas.
A marker symbol type, for rendering Point and MultiPoint geometries.
void setSize(double size) const
Sets the size for the whole symbol.
static std::unique_ptr< 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.
static void addRecentColor(const QColor &color)
Adds a color to the list of recent colors.
Stores properties relating to a screen.
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
static std::unique_ptr< 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, const QgsScreenProperties &screen=QgsScreenProperties())
Returns a pixmap preview for a color ramp.
static std::unique_ptr< 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, const QgsScreenProperties &screen=QgsScreenProperties())
Returns an icon preview for a color ramp.
static std::unique_ptr< QMimeData > colorToMimeData(const QColor &color)
Creates mime data from a color.
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.
virtual QgsSymbol * clone() const =0
Returns a deep copy of this symbol.
static std::unique_ptr< QgsSymbol > defaultSymbol(Qgis::GeometryType geomType)
Returns a new default symbol for the specified geometry type.
Represents a vector layer which manages a vector based dataset.
int scaleIconSize(int standardSize)
Scales an icon size to compensate for display pixel density, making the icon size hi-dpi friendly,...