QGIS API Documentation 3.37.0-Master (fdefdf9c27f)
qgslegendpatchshapebutton.cpp
Go to the documentation of this file.
1/***************************************************************************
2 qgslegendpatchshapebutton.cpp
3 -----------------
4 Date : April 2020
5 Copyright : (C) 2020 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
18#include "qgis.h"
19#include "qgsguiutils.h"
20#include "qgsfillsymbol.h"
21#include "qgsmarkersymbol.h"
22#include "qgslinesymbol.h"
23
24#include <QMenu>
25#include <QBuffer>
26
27QgsLegendPatchShapeButton::QgsLegendPatchShapeButton( QWidget *parent, const QString &dialogTitle )
28 : QToolButton( parent )
29 , mShape( QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Fill, QSizeF( 10, 5 ) ) )
30 , mDialogTitle( dialogTitle.isEmpty() ? tr( "Legend Patch Shape" ) : dialogTitle )
31{
32 mPreviewSymbol.reset( QgsFillSymbol::createSimple( QVariantMap() ) );
33
34 connect( this, &QAbstractButton::clicked, this, &QgsLegendPatchShapeButton::showSettingsDialog );
35
36 //setup dropdown menu
37 mMenu = new QMenu( this );
38 connect( mMenu, &QMenu::aboutToShow, this, &QgsLegendPatchShapeButton::prepareMenu );
39 setMenu( mMenu );
40 setPopupMode( QToolButton::MenuButtonPopup );
41
42 //make sure height of button looks good under different platforms
43 QSize size = QToolButton::minimumSizeHint();
44 int fontHeight = static_cast< int >( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 2.0 );
45 mSizeHint = QSize( size.width(), std::max( size.height(), fontHeight ) );
46}
47
49
51{
52 return mSizeHint;
53}
54
56{
57 return mSizeHint;
58}
59
61{
62 if ( mPreviewSymbol->type() != type )
63 {
64 switch ( type )
65 {
67 mPreviewSymbol.reset( QgsMarkerSymbol::createSimple( QVariantMap() ) );
68 break;
69
71 mPreviewSymbol.reset( QgsLineSymbol::createSimple( QVariantMap() ) );
72 break;
73
75 mPreviewSymbol.reset( QgsFillSymbol::createSimple( QVariantMap() ) );
76 break;
77
79 break;
80 }
81 }
82
83 if ( type != mType )
84 {
85 mType = type;
87 }
88
89 updatePreview();
90}
91
93{
94 mPreviewSymbol.reset( symbol );
95 updatePreview();
96}
97
98void QgsLegendPatchShapeButton::showSettingsDialog()
99{
101 if ( panel && panel->dockMode() )
102 {
103 QgsLegendPatchShapeWidget *widget = new QgsLegendPatchShapeWidget( this, mShape );
104 connect( widget, &QgsLegendPatchShapeWidget::changed, this, [ = ]
105 {
106 setShape( widget->shape() );
107 } );
108 widget->setPanelTitle( mDialogTitle );
109 panel->openPanel( widget );
110 }
111}
112
114{
115 switch ( mType )
116 {
118 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Marker, QSizeF( 10, 5 ) );
119 break;
120
122 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Line, QSizeF( 10, 5 ) );
123 break;
124
126 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Fill, QSizeF( 10, 5 ) );
127 break;
128
130 break;
131 }
132 mIsDefault = true;
133 updatePreview();
134 emit changed();
135}
136
138{
139 mMessageBar = bar;
140}
141
143{
144 return mMessageBar;
145}
146
148{
149 mShape = shape.symbolType() == mType ? shape : QgsLegendPatchShape();
150 mIsDefault = mShape.isNull();
151 if ( mIsDefault )
152 {
153 switch ( mType )
154 {
156 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Marker, QSizeF( 10, 5 ) );
157 break;
158
160 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Line, QSizeF( 10, 5 ) );
161 break;
162
164 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Fill, QSizeF( 10, 5 ) );
165 break;
166
168 break;
169 }
170 }
171
172 updatePreview();
173 emit changed();
174}
175
177{
178 if ( e->button() == Qt::RightButton )
179 {
180 QToolButton::showMenu();
181 return;
182 }
183 QToolButton::mousePressEvent( e );
184}
185
186void QgsLegendPatchShapeButton::prepareMenu()
187{
188 mMenu->clear();
189
190 QAction *configureAction = new QAction( tr( "Configure Patch…" ), this );
191 mMenu->addAction( configureAction );
192 connect( configureAction, &QAction::triggered, this, &QgsLegendPatchShapeButton::showSettingsDialog );
193
194 QAction *defaultAction = new QAction( tr( "Reset to Default" ), this );
195 mMenu->addAction( defaultAction );
196 connect( defaultAction, &QAction::triggered, this, [ = ] { setToDefault(); emit changed(); } );
197
198 mMenu->addSeparator();
199
201 patchNames.sort();
202 const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
203 for ( const QString &name : std::as_const( patchNames ) )
204 {
206 if ( shape.symbolType() == mType )
207 {
208 if ( const QgsSymbol *symbol = QgsStyle::defaultStyle()->previewSymbolForPatchShape( shape ) )
209 {
210 QIcon icon = QgsSymbolLayerUtils::symbolPreviewPixmap( symbol, QSize( iconSize, iconSize ), 1, nullptr, false, nullptr, &shape, QgsScreenProperties( screen() ) );
211 QAction *action = new QAction( name, this );
212 action->setIcon( icon );
213 connect( action, &QAction::triggered, this, [ = ] { loadPatchFromStyle( name ); } );
214 mMenu->addAction( action );
215 }
216 }
217 }
218}
219
220void QgsLegendPatchShapeButton::loadPatchFromStyle( const QString &name )
221{
222 if ( !QgsStyle::defaultStyle()->legendPatchShapeNames().contains( name ) )
223 return;
224
226 setShape( newShape );
227}
228
230{
231 if ( e->type() == QEvent::EnabledChange )
232 {
233 updatePreview();
234 }
235 QToolButton::changeEvent( e );
236}
237
239{
240 updatePreview();
241 QToolButton::showEvent( e );
242}
243
244void QgsLegendPatchShapeButton::resizeEvent( QResizeEvent *event )
245{
246 QToolButton::resizeEvent( event );
247 //recalculate icon size and redraw icon
248 mIconSize = QSize();
249 updatePreview();
250}
251
252void QgsLegendPatchShapeButton::updatePreview()
253{
254 QSize currentIconSize;
255 //icon size is button size with a small margin
256 if ( menu() )
257 {
258 if ( !mIconSize.isValid() )
259 {
260 //calculate size of push button part of widget (ie, without the menu dropdown button part)
261 QStyleOptionToolButton opt;
262 initStyleOption( &opt );
263 QRect buttonSize = QApplication::style()->subControlRect( QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton,
264 this );
265 //make sure height of icon looks good under different platforms
266#ifdef Q_OS_WIN
267 mIconSize = QSize( buttonSize.width() - 10, height() - 6 );
268#else
269 mIconSize = QSize( buttonSize.width() - 10, height() - 12 );
270#endif
271 }
272 currentIconSize = mIconSize;
273 }
274 else
275 {
276 //no menu
277#ifdef Q_OS_WIN
278 currentIconSize = QSize( width() - 10, height() - 6 );
279#else
280 currentIconSize = QSize( width() - 10, height() - 12 );
281#endif
282 }
283
284 if ( !currentIconSize.isValid() || currentIconSize.width() <= 0 || currentIconSize.height() <= 0 )
285 {
286 return;
287 }
288
289 //create an icon pixmap
290 QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( mPreviewSymbol.get(), currentIconSize, currentIconSize.height() / 10, &mShape, QgsScreenProperties( screen() ) );
291 setIconSize( currentIconSize );
292 setIcon( icon );
293
294 // set tooltip
295 // create very large preview image
296
297 int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 23 );
298 int height = static_cast< int >( width / 1.61803398875 ); // golden ratio
299
300 QPixmap pm = QgsSymbolLayerUtils::symbolPreviewPixmap( mPreviewSymbol.get(), QSize( width, height ), height / 20, nullptr, false, nullptr, &mShape, QgsScreenProperties( screen() ) );
301 QByteArray data;
302 QBuffer buffer( &data );
303 pm.save( &buffer, "PNG", 100 );
304 setToolTip( QStringLiteral( "<img src='data:image/png;base64, %3' width=\"%4\">" ).arg( QString( data.toBase64() ) ).arg( width ) );
305}
306
308{
309 mDialogTitle = title;
310}
311
313{
314 return mDialogTitle;
315}
316
318{
319 return mIsDefault ? QgsLegendPatchShape() : mShape;
320}
The Qgis class provides global constants for use throughout the application.
Definition: qgis.h:54
SymbolType
Symbol types.
Definition: qgis.h:401
@ Marker
Marker symbol.
@ Line
Line symbol.
@ Fill
Fill symbol.
@ Hybrid
Hybrid symbol.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition: qgis.h:4927
static QgsFillSymbol * createSimple(const QVariantMap &properties)
Create a fill symbol with one symbol layer: SimpleFill with specified properties.
void setSymbolType(Qgis::SymbolType type)
Sets the symbol type which the button requires.
void setToDefault()
Resets the shape to the default shape.
QgsLegendPatchShapeButton(QWidget *parent=nullptr, const QString &dialogTitle=QString())
Construct a new patch shape button with the specified parent widget.
QgsMessageBar * messageBar() const
Returns the message bar associated with the widget.
QgsLegendPatchShape shape()
Returns the current shape defined by the button.
void changeEvent(QEvent *e) override
void setDialogTitle(const QString &title)
Sets the title for the symbol settings dialog window.
void mousePressEvent(QMouseEvent *e) override
void resizeEvent(QResizeEvent *event) override
void changed()
Emitted when the shape's settings are changed.
QString dialogTitle() const
Returns the title for the symbol settings dialog window.
void setShape(const QgsLegendPatchShape &shape)
Sets the shape for the button.
QSize minimumSizeHint() const override
void setPreviewSymbol(QgsSymbol *symbol)
Sets the symbol to use for previewing the legend patch shape.
~QgsLegendPatchShapeButton() override
void setMessageBar(QgsMessageBar *bar)
Sets the message bar associated with the widget.
void showEvent(QShowEvent *e) override
Widget for configuring a custom legend patch shape.
QgsLegendPatchShape shape() const
Returns the legend patch shape as currently defined by the widget.
void changed()
Emitted whenever the patch shape defined by the widget is changed.
Represents a patch shape for use in map legends.
bool isNull() const
Returns true if the patch shape is a null QgsLegendPatchShape, which indicates that the default legen...
Qgis::SymbolType symbolType() const
Returns the symbol type associated with this patch.
static QgsLineSymbol * createSimple(const QVariantMap &properties)
Create a line symbol with one symbol layer: SimpleLine with specified properties.
static QgsMarkerSymbol * createSimple(const QVariantMap &properties)
Create a marker symbol with one symbol layer: SimpleMarker with specified properties.
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 ...
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.
Stores properties relating to a screen.
QgsLegendPatchShape defaultPatch(Qgis::SymbolType type, QSizeF size) const
Returns the default legend patch shape for the given symbol type.
Definition: qgsstyle.cpp:1189
@ LegendPatchShapeEntity
Legend patch shape (since QGIS 3.14)
Definition: qgsstyle.h:186
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition: qgsstyle.cpp:145
QStringList symbolsOfFavorite(StyleEntity type) const
Returns the symbol names which are flagged as favorite.
Definition: qgsstyle.cpp:1333
QgsLegendPatchShape legendPatchShape(const QString &name) const
Returns the legend patch shape with the specified name.
Definition: qgsstyle.cpp:2177
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 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.
Abstract base class for all rendered symbols.
Definition: qgssymbol.h:94
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,...