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