QGIS API Documentation 3.41.0-Master (3c143d501a8)
Loading...
Searching...
No Matches
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
17#include "moc_qgslegendpatchshapebutton.cpp"
19#include "qgis.h"
20#include "qgsguiutils.h"
21#include "qgsfillsymbol.h"
22#include "qgsmarkersymbol.h"
23#include "qgslinesymbol.h"
24
25#include <QMenu>
26#include <QBuffer>
27
28QgsLegendPatchShapeButton::QgsLegendPatchShapeButton( QWidget *parent, const QString &dialogTitle )
29 : QToolButton( parent )
30 , mShape( QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Fill, QSizeF( 10, 5 ) ) )
31 , mDialogTitle( dialogTitle.isEmpty() ? tr( "Legend Patch Shape" ) : dialogTitle )
32{
33 mPreviewSymbol.reset( QgsFillSymbol::createSimple( QVariantMap() ) );
34
35 connect( this, &QAbstractButton::clicked, this, &QgsLegendPatchShapeButton::showSettingsDialog );
36
37 //setup dropdown menu
38 mMenu = new QMenu( this );
39 connect( mMenu, &QMenu::aboutToShow, this, &QgsLegendPatchShapeButton::prepareMenu );
40 setMenu( mMenu );
41 setPopupMode( QToolButton::MenuButtonPopup );
42
43 //make sure height of button looks good under different platforms
44 QSize size = QToolButton::minimumSizeHint();
45 int fontHeight = static_cast< int >( Qgis::UI_SCALE_FACTOR * fontMetrics().height() * 2.0 );
46 mSizeHint = QSize( size.width(), std::max( size.height(), fontHeight ) );
47}
48
50
52{
53 return mSizeHint;
54}
55
57{
58 return mSizeHint;
59}
60
62{
63 if ( mPreviewSymbol->type() != type )
64 {
65 switch ( type )
66 {
68 mPreviewSymbol.reset( QgsMarkerSymbol::createSimple( QVariantMap() ) );
69 break;
70
72 mPreviewSymbol.reset( QgsLineSymbol::createSimple( QVariantMap() ) );
73 break;
74
76 mPreviewSymbol.reset( QgsFillSymbol::createSimple( QVariantMap() ) );
77 break;
78
80 break;
81 }
82 }
83
84 if ( type != mType )
85 {
86 mType = type;
88 }
89
90 updatePreview();
91}
92
94{
95 mPreviewSymbol.reset( symbol );
96 updatePreview();
97}
98
99void QgsLegendPatchShapeButton::showSettingsDialog()
100{
102 if ( panel && panel->dockMode() )
103 {
104 QgsLegendPatchShapeWidget *widget = new QgsLegendPatchShapeWidget( this, mShape );
105 connect( widget, &QgsLegendPatchShapeWidget::changed, this, [ = ]
106 {
107 setShape( widget->shape() );
108 } );
109 widget->setPanelTitle( mDialogTitle );
110 panel->openPanel( widget );
111 }
112}
113
115{
116 switch ( mType )
117 {
119 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Marker, QSizeF( 10, 5 ) );
120 break;
121
123 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Line, QSizeF( 10, 5 ) );
124 break;
125
127 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Fill, QSizeF( 10, 5 ) );
128 break;
129
131 break;
132 }
133 mIsDefault = true;
134 updatePreview();
135 emit changed();
136}
137
139{
140 mMessageBar = bar;
141}
142
144{
145 return mMessageBar;
146}
147
149{
150 mShape = shape.symbolType() == mType ? shape : QgsLegendPatchShape();
151 mIsDefault = mShape.isNull();
152 if ( mIsDefault )
153 {
154 switch ( mType )
155 {
157 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Marker, QSizeF( 10, 5 ) );
158 break;
159
161 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Line, QSizeF( 10, 5 ) );
162 break;
163
165 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Fill, QSizeF( 10, 5 ) );
166 break;
167
169 break;
170 }
171 }
172
173 updatePreview();
174 emit changed();
175}
176
178{
179 if ( e->button() == Qt::RightButton )
180 {
181 QToolButton::showMenu();
182 return;
183 }
184 QToolButton::mousePressEvent( e );
185}
186
187void QgsLegendPatchShapeButton::prepareMenu()
188{
189 mMenu->clear();
190
191 QAction *configureAction = new QAction( tr( "Configure Patch…" ), this );
192 mMenu->addAction( configureAction );
193 connect( configureAction, &QAction::triggered, this, &QgsLegendPatchShapeButton::showSettingsDialog );
194
195 QAction *defaultAction = new QAction( tr( "Reset to Default" ), this );
196 mMenu->addAction( defaultAction );
197 connect( defaultAction, &QAction::triggered, this, [ = ] { setToDefault(); emit changed(); } );
198
199 mMenu->addSeparator();
200
202 patchNames.sort();
203 const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
204 for ( const QString &name : std::as_const( patchNames ) )
205 {
207 if ( shape.symbolType() == mType )
208 {
209 if ( const QgsSymbol *symbol = QgsStyle::defaultStyle()->previewSymbolForPatchShape( shape ) )
210 {
211 QIcon icon = QgsSymbolLayerUtils::symbolPreviewPixmap( symbol, QSize( iconSize, iconSize ), 1, nullptr, false, nullptr, &shape, QgsScreenProperties( screen() ) );
212 QAction *action = new QAction( name, this );
213 action->setIcon( icon );
214 connect( action, &QAction::triggered, this, [ = ] { loadPatchFromStyle( name ); } );
215 mMenu->addAction( action );
216 }
217 }
218 }
219}
220
221void QgsLegendPatchShapeButton::loadPatchFromStyle( const QString &name )
222{
223 if ( !QgsStyle::defaultStyle()->legendPatchShapeNames().contains( name ) )
224 return;
225
227 setShape( newShape );
228}
229
231{
232 if ( e->type() == QEvent::EnabledChange )
233 {
234 updatePreview();
235 }
236 QToolButton::changeEvent( e );
237}
238
240{
241 updatePreview();
242 QToolButton::showEvent( e );
243}
244
245void QgsLegendPatchShapeButton::resizeEvent( QResizeEvent *event )
246{
247 QToolButton::resizeEvent( event );
248 //recalculate icon size and redraw icon
249 mIconSize = QSize();
250 updatePreview();
251}
252
253void QgsLegendPatchShapeButton::updatePreview()
254{
255 QSize currentIconSize;
256 //icon size is button size with a small margin
257 if ( menu() )
258 {
259 if ( !mIconSize.isValid() )
260 {
261 //calculate size of push button part of widget (ie, without the menu dropdown button part)
262 QStyleOptionToolButton opt;
263 initStyleOption( &opt );
264 QRect buttonSize = QApplication::style()->subControlRect( QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton,
265 this );
266 //make sure height of icon looks good under different platforms
267#ifdef Q_OS_WIN
268 mIconSize = QSize( buttonSize.width() - 10, height() - 6 );
269#else
270 mIconSize = QSize( buttonSize.width() - 10, height() - 12 );
271#endif
272 }
273 currentIconSize = mIconSize;
274 }
275 else
276 {
277 //no menu
278#ifdef Q_OS_WIN
279 currentIconSize = QSize( width() - 10, height() - 6 );
280#else
281 currentIconSize = QSize( width() - 10, height() - 12 );
282#endif
283 }
284
285 if ( !currentIconSize.isValid() || currentIconSize.width() <= 0 || currentIconSize.height() <= 0 )
286 {
287 return;
288 }
289
290 //create an icon pixmap
291 QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( mPreviewSymbol.get(), currentIconSize, currentIconSize.height() / 10, &mShape, QgsScreenProperties( screen() ) );
292 setIconSize( currentIconSize );
293 setIcon( icon );
294
295 // set tooltip
296 // create very large preview image
297
298 int width = static_cast< int >( Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 23 );
299 int height = static_cast< int >( width / 1.61803398875 ); // golden ratio
300
301 QPixmap pm = QgsSymbolLayerUtils::symbolPreviewPixmap( mPreviewSymbol.get(), QSize( width, height ), height / 20, nullptr, false, nullptr, &mShape, QgsScreenProperties( screen() ) );
302 QByteArray data;
303 QBuffer buffer( &data );
304 pm.save( &buffer, "PNG", 100 );
305 setToolTip( QStringLiteral( "<img src='data:image/png;base64, %3' width=\"%4\">" ).arg( QString( data.toBase64() ) ).arg( width ) );
306}
307
309{
310 mDialogTitle = title;
311}
312
314{
315 return mDialogTitle;
316}
317
319{
320 return mIsDefault ? QgsLegendPatchShape() : mShape;
321}
The Qgis class provides global constants for use throughout the application.
Definition qgis.h:54
SymbolType
Symbol types.
Definition qgis.h:574
@ Marker
Marker symbol.
@ Line
Line symbol.
@ Fill
Fill symbol.
@ Hybrid
Hybrid symbol.
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition qgis.h:5733
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 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.
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.
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.
@ LegendPatchShapeEntity
Legend patch shape.
Definition qgsstyle.h:210
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:146
QStringList symbolsOfFavorite(StyleEntity type) const
Returns the symbol names which are flagged as favorite.
QgsLegendPatchShape legendPatchShape(const QString &name) const
Returns the legend patch shape with the specified name.
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:231
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,...