QGIS API Documentation 4.1.0-Master (5bf3c20f3c9)
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] { setShape( widget->shape() ); } );
111 widget->setPanelTitle( mDialogTitle );
112 panel->openPanel( widget );
113 }
114}
115
117{
118 switch ( mType )
119 {
121 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Marker, QSizeF( 10, 5 ) );
122 break;
123
125 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Line, QSizeF( 10, 5 ) );
126 break;
127
129 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Fill, QSizeF( 10, 5 ) );
130 break;
131
133 break;
134 }
135 mIsDefault = true;
136 updatePreview();
137 emit changed();
138}
139
141{
142 mMessageBar = bar;
143}
144
146{
147 return mMessageBar;
148}
149
151{
152 mShape = shape.symbolType() == mType ? shape : QgsLegendPatchShape();
153 mIsDefault = mShape.isNull();
154 if ( mIsDefault )
155 {
156 switch ( mType )
157 {
159 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Marker, QSizeF( 10, 5 ) );
160 break;
161
163 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Line, QSizeF( 10, 5 ) );
164 break;
165
167 mShape = QgsStyle::defaultStyle()->defaultPatch( Qgis::SymbolType::Fill, QSizeF( 10, 5 ) );
168 break;
169
171 break;
172 }
173 }
174
175 updatePreview();
176 emit changed();
177}
178
180{
181 if ( e->button() == Qt::RightButton )
182 {
183 QToolButton::showMenu();
184 return;
185 }
186 QToolButton::mousePressEvent( e );
187}
188
189void QgsLegendPatchShapeButton::prepareMenu()
190{
191 mMenu->clear();
192
193 QAction *configureAction = new QAction( tr( "Configure Patch…" ), this );
194 mMenu->addAction( configureAction );
195 connect( configureAction, &QAction::triggered, this, &QgsLegendPatchShapeButton::showSettingsDialog );
196
197 QAction *defaultAction = new QAction( tr( "Reset to Default" ), this );
198 mMenu->addAction( defaultAction );
199 connect( defaultAction, &QAction::triggered, this, [this] {
200 setToDefault();
201 emit changed();
202 } );
203
204 mMenu->addSeparator();
205
207 patchNames.sort();
208 const int iconSize = QgsGuiUtils::scaleIconSize( 16 );
209 for ( const QString &name : std::as_const( patchNames ) )
210 {
211 const QgsLegendPatchShape shape = QgsStyle::defaultStyle()->legendPatchShape( name );
212 if ( shape.symbolType() == mType )
213 {
214 if ( const QgsSymbol *symbol = QgsStyle::defaultStyle()->previewSymbolForPatchShape( shape ) )
215 {
216 QIcon icon = QgsSymbolLayerUtils::symbolPreviewPixmap( symbol, QSize( iconSize, iconSize ), 1, nullptr, false, nullptr, &shape, QgsScreenProperties( screen() ) );
217 QAction *action = new QAction( name, this );
218 action->setIcon( icon );
219 connect( action, &QAction::triggered, this, [this, name] { loadPatchFromStyle( name ); } );
220 mMenu->addAction( action );
221 }
222 }
223 }
224}
225
226void QgsLegendPatchShapeButton::loadPatchFromStyle( const QString &name )
227{
228 if ( !QgsStyle::defaultStyle()->legendPatchShapeNames().contains( name ) )
229 return;
230
231 const QgsLegendPatchShape newShape = QgsStyle::defaultStyle()->legendPatchShape( name );
232 setShape( newShape );
233}
234
236{
237 if ( e->type() == QEvent::EnabledChange )
238 {
239 updatePreview();
240 }
241 QToolButton::changeEvent( e );
242}
243
245{
246 updatePreview();
247 QToolButton::showEvent( e );
248}
249
250void QgsLegendPatchShapeButton::resizeEvent( QResizeEvent *event )
251{
252 QToolButton::resizeEvent( event );
253 //recalculate icon size and redraw icon
254 mIconSize = QSize();
255 updatePreview();
256}
257
258void QgsLegendPatchShapeButton::updatePreview()
259{
260 QSize currentIconSize;
261 //icon size is button size with a small margin
262 if ( menu() )
263 {
264 if ( !mIconSize.isValid() )
265 {
266 //calculate size of push button part of widget (ie, without the menu dropdown button part)
267 QStyleOptionToolButton opt;
268 initStyleOption( &opt );
269 QRect buttonSize = QApplication::style()->subControlRect( QStyle::CC_ToolButton, &opt, QStyle::SC_ToolButton, this );
270 //make sure height of icon looks good under different platforms
271#ifdef Q_OS_WIN
272 mIconSize = QSize( buttonSize.width() - 10, height() - 6 );
273#else
274 mIconSize = QSize( buttonSize.width() - 10, height() - 12 );
275#endif
276 }
277 currentIconSize = mIconSize;
278 }
279 else
280 {
281 //no menu
282#ifdef Q_OS_WIN
283 currentIconSize = QSize( width() - 10, height() - 6 );
284#else
285 currentIconSize = QSize( width() - 10, height() - 12 );
286#endif
287 }
288
289 if ( !currentIconSize.isValid() || currentIconSize.width() <= 0 || currentIconSize.height() <= 0 )
290 {
291 return;
292 }
293
294 //create an icon pixmap
295 QIcon icon = QgsSymbolLayerUtils::symbolPreviewIcon( mPreviewSymbol.get(), currentIconSize, currentIconSize.height() / 10, &mShape, QgsScreenProperties( screen() ) );
296 setIconSize( currentIconSize );
297 setIcon( icon );
298
299 // set tooltip
300 // create very large preview image
301
302 int width = static_cast<int>( Qgis::UI_SCALE_FACTOR * fontMetrics().horizontalAdvance( 'X' ) * 23 );
303 int height = static_cast<int>( width / 1.61803398875 ); // golden ratio
304
305 QPixmap pm = QgsSymbolLayerUtils::symbolPreviewPixmap( mPreviewSymbol.get(), QSize( width, height ), height / 20, nullptr, false, nullptr, &mShape, QgsScreenProperties( screen() ) );
306 QByteArray data;
307 QBuffer buffer( &data );
308 pm.save( &buffer, "PNG", 100 );
309 setToolTip( u"<img src='data:image/png;base64, %3' width=\"%4\">"_s.arg( QString( data.toBase64() ) ).arg( width ) );
310}
311
313{
314 mDialogTitle = title;
315}
316
318{
319 return mDialogTitle;
320}
321
323{
324 return mIsDefault ? QgsLegendPatchShape() : mShape;
325}
Provides global constants and enumerations for use throughout the application.
Definition qgis.h:62
SymbolType
Symbol types.
Definition qgis.h:636
@ Marker
Marker symbol.
Definition qgis.h:637
@ Line
Line symbol.
Definition qgis.h:638
@ Fill
Fill symbol.
Definition qgis.h:639
@ Hybrid
Hybrid symbol.
Definition qgis.h:640
static const double UI_SCALE_FACTOR
UI scaling factor.
Definition qgis.h:6591
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:211
static QgsStyle * defaultStyle(bool initialize=true)
Returns the default application-wide style.
Definition qgsstyle.cpp:148
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:227
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,...